全局环境
前端结构
模块化
Zero UI中处理模块弃用了相对路径模式,整个导入过程直接使用模块导入的方式,类似:
import Ux from 'ux';
一来方便做重构、二来方便做整体迁移,模块定义位于项目中的 config/modules.js 中,您可以从源代码中看到目前规划的模块所有信息,模块主要如下:
-
内部模块:做Zero UI和Zero Extension框架研发才会使用的模块,必须是按调用层次执行导入(下层模块不可导入上层模块)。
-
外部模块:这部分模块才是开发人员可以使用的模块,如
Ux, Ex, Sk, Ui等。
Zero UI中的完整模块参考下表(只有内部模块按排序执行,外部模块不遵循文件名排序规则):
| 模块名 | 类型 | 路径 | 含义 |
|---|---|---|---|
app |
|
|
应用级自定义模块专用存放目录。 |
mock |
|
|
纯前端运行的Mock模拟数据专用目录。 |
plugin |
|
|
应用级插件专用存放目录。 |
entity |
|
|
Zero 数据模型外部专用模块。 |
web |
|
|
(标准组件)Zero UI组件外部专用模块。 |
oi |
|
|
(配置组件)Zero UI配置化专用组件目录。 |
ei |
|
|
(扩展组件)Zero UI扩展组件专用目录。 |
ex |
|
|
扩展工具库 |
ui |
|
|
快速开发库 |
ux |
|
|
标准工具库 |
environment |
|
|
环境专用模块,用于存储当前系统环境中的全局配置信息。 |
lang |
|
|
资源目录专用模块。 |
zei |
|
|
内部扩展呈现库,Zero Extension Interface。 |
zep |
|
|
内部扩展处理库,Zero Extension Processor。 |
zet |
|
|
内部扩展工具库,Zero Extension Toolkit。 |
zero |
|
|
对接层(复杂组件),Zero(Aeon Interface)。 |
zs |
|
|
子系统层(交互式组件),Zero Subsystem。 |
zi |
|
|
交互式组件接口抽象层,Zero Interface。 |
zmr |
|
|
查询模型层,Zero Model Qr Engine。 |
zo |
|
|
组件起源层(从这层开始有组件概念),Zero Origin Component。 |
zme |
|
|
环境模型层,Zero Model for Environment。 |
zone |
|
|
环境区域底座,Zero Zone。 |
skin |
|
|
皮肤管理器,最底层的多风格样式导入。 |
style |
|
|
样式管理器。 |
好了,问题来了,整个框架这么多模块,那么作为开发人员应该如何使用呢?上述模块除了 z 前缀的模块遵循上下层的排序(排在上边的调用下边),其他模块不遵循该法则(历史原因),所以整体从上往下的层级关系如下:
ui # import Ui from 'ui';
ei / oi # 由于很多时候都采用API模式,所以这两个库一般开发过程中很少用
ex # import Ex from 'ex';
zei
zep
zet
plugin # import Plugin from 'plugin';
ux # import Ux from 'ux';
zero
entity # import {xxx} from 'entity';
zs
web # import {xxx} from 'web';
zi
environment # import {xxx} from 'environment';
zmr
zo
zme
zone
skin # import Sk from 'skin';
style # @import "~style/index"; # SCSS 模式
上述结构就是整体的调用结构,排序从上往下,开发人员只需要关注行内有注释的部分,您可以按表格中的图标来区分,此处提供开发人员使用模块的黄金法则:
| 模块 | 更改 | 使用 | 含义 |
|---|---|---|---|
o |
o |
自定义模块,自由修改。 |
|
x |
o |
开发人员可直接使用 |
|
x |
x |
开发人员不可以直接 |
|
因为历史原因,其实开发人员真正在开发过程中通常只会使用
从代码片段就可以知道这种方式的结构最大的好处,就是可以将整个目录中的内容完整移动到另外的目录下执行,这样重构就变得特别容易了。 |
最后说一句,您也可以修改 config/modules.js 扩展自己想要的模块,只要不破坏本章中提到的整体调用结构即可。
应用结构
前文提到了 app 前缀的部分,是开发人员的自定义模块,除开这部分内容以及前边介绍的模块化之外,您的代码目录中应该还剩下:
-
container:模板专用目录
-
components:页面专用目录
二者的完整结构如下:
一个前端站点的页面主要包含两部分:模板页和内容页,模板页位于 container 中,内容页则位于 components 中,最终形成的结构如上图所示。内容页和模板的关联关系有两种定义方法:
| 定义方式 | 含义 |
|---|---|
全局路由表 |
直接在
这种方式是最早的方式,整体设计的确很方便区分不同页面对应的模板,但过于集中化,这种模式只需要在 |
页面路由表 |
直接在
这种方式是新模式,缺点是除开默认页面以外,可能其他所有页面都需要定义 |
开发入门
多语言环境下的Cab
Cab多语言环境的支持是Zero UI中的一个亮点,您可以在Zero UI按自己需求随时扩展不同语言级的模块实现多语言环境,语言处理步骤如下:
-
在您的环境变量文件:
.env.development或.env.production中配置Z_LANGUAGE环境变量,如cn。 -
从
cab模块中读取对应目录下的内容,如cn则读取资源文件的根目录走cab/cn。 -
解析模块对应的
Cab.json中的名空间( ns ),名空间决定了资源文件的目录路径。 -
根据最终
@Ux.zero绑定的文件名( cab("xxx") )来决定读取哪个资源文件。
|
在Zero UI中开发时,若您想要实现 多语言 模式,则禁止在您的页面代码中出现任何常量显示文本,如下边这种写法:
而是直接使用资源文件绑定来实现,将所有呈现文字放到资源文件中,若您想要切换到另外的语言版本,则可以直接翻译之后替换同名文件包,如将 |
资源关联拓扑
Zero UI中的资源引用拓扑图如下(同时包含模板页和内容页):
从图上可以看到,模板的绑定和页面的绑定是分别执行,而绑定过程中还会受到 Z_LANGUAGE 和 Z_ROUTE 环境变量的影响:
-
Z_LANGUAGE:控制当前应用读取的资源包的语言。 -
Z_ROUTE:控制当前应用的 一级路径 (通常表示应用)。
固定入口文件是 UI.js ,若您创建了新的页面,需要重新启动容器(执行 run-zero.sh / run-zero.bat)才能生效,核心链接文件参考下表:
| 链接类型 | 路径 |
|---|---|
内容页链接 |
|
模板页链接 |
|
扩展页链接 |
|
|
示例:代码演示
若要实现上述资源引用部分的代码,您只需要按如下步骤进行:
|
假设环境变量:
假设您想要的页面为订单处理页:
|
-
在
cab/cn/中创建您的资源文件:components/order/process/UI.json。名空间资源绑定文件并没有严格要求一定要按照页面层级关系定义,但是推荐和您的
components下的<module>/<page>保持一致以防止混乱,方便维护。 -
在
src/components中创建您的目录以及入口文件:order/process/UI.js,创建之后重启容器:run-zero.bat / run-zero.sh。 -
在您的代码目录中创建
Cab.json的名空间文件,并指向名空间目录:{ "ns": "components/order/process" } -
在您的
UI.js中追加如下代码:import Ux from 'ux'; // 注解修饰 @Ux.zero(Ux.rxEtat(require("./Cab")) // 此处的 UI 证明它绑定的文件名为 UI.json .cab("UI") .to() ) // 类定义 class Component extends React.PureComponent{ // 核心渲染方法 render(){ // 读取 UI.json 中的信息 const info = Ux.inHoc(this, "info"); const info1 = Ux.fromHoc(this, "info"); return ... } } // 组件导出 export default Component
|
上述代码示例中
重点:此处的资源文件所有根节点都必须带 |
常用组件
日志器
日志器在 Zero Extension 会将部分 彩色日志 打印在浏览器的开发工具 console 中,常使用的 骨架代码 如:
return Ex.yoRender(this, () => {
// ....
}, Ex.parserOfColor("PxRBACGroup").page());
您可以调用 Ex.parserOfColor 方法构造 日志器生成器 对象,之后调用对应的方法实现日志器的选择,上述骨架代码中使用了 page 类型的日志器。
| 可用日志器 | 使用场景 |
|---|---|
|
内部自定义 |
|
私有组件 |
|
表单组件 |
|
列表组件 |
|
列表四个区域专用 |
|
模板页 |
|
公有组件 |
|
容器专用,对应 |
|
页面组件,对应 |
|
带有 |
|
自定义组件 |
|
动态配置页 |
|
视图组件(仅查看,包括报表页) |
|
用户自定义页面,对应 |
|
(开发中心)工具开发专用 |
|
(开发中心)标准化专用 |
上述 日志器 并不存在严格规定,只是一种约定,根据目前开发过的所有项目的一个不成文的软文,您也可以根据自身情况选择不同的 日志器 来辅助开发 或自定义更多日志器帮助开发人员监控开发过程中的所有日志。
Assist 辅助数据
Assist 在整个 Zero Extension 中已经成为了一种概念:辅助数据,又或者称为关联数据,一般用来描述主要管理模块中与之相关的其他表中的数据,让主模型的属性变成可管理型的模块数据。常用的辅助数据加载配置如下:
-
_assist:这种节点通常位于当前某个页面的UI.json配置文件中,一旦使用@Ux.zero加载过资源文件之后可直接在componentDidMount中调用对应的API加载,最终更新到状态中。 -
xxx.assist:这种节点一般位于组件内部,如_form.assist属于表单内部的辅助数据。
Zero Extension中有三种常见的辅助数据( Assist / Datum 语义):
| 辅助数据类型 | 含义 |
|---|---|
|
列表类辅助数据,主要访问 |
|
分类辅助数据,主要访问 |
|
带有Ajax配置和定义的辅助数据,可以访问任何一张系统中的表,通常依赖您开放出来的接口,此接口不可通用,所以用户可定制。 |
定义和消费
Assist 数据的基本规范如下
-
所有的字典都会有一个名字,在 Zero 框架中使用单词
DATUM来描述,这个名字通常格式是 :prefix.name: -
此处
prefix表示当前字典数据的前缀,而name则是字典本身的相关信息,一般同一类型的字典拥有相同的prefix,需注意的是当前页面定义的 辅助数据 的名称必须是唯一的。 -
在消费绑定时候,字典的名称会直接使用
source=prefix.name的方式进行 辅助数据 绑定以及消费。 -
辅助数据和字典数据在
React组件中一般会存在于 props 或 state 中,每个字典的命名规则使用$a_prefix_name或$t_prefix_name,为了开发人员简化处理,所有 API 中的传入参数依旧使用prefix.name(您不用去关心组件中变量使用的是什么,仅需要在调试时知道如何识别即可)。
参考如下定义:
{
"_assist": {
"ajax.groups": {
"uri": "/api/group/by/sigma"
},
"ajax.groups.type": {
"uri": "/api/type/tabulars/:type",
"magic": {
"type": "FIX:zero.group.type"
}
}
}
}
从定义可以知道此处的 Assist 辅助数据的数据结构和 Ajax 定义很近似,都包含了 uri, method 等和远程通信相关的基础配置,包括参数中支持 输入解析器 的配置格式。上述示例中定义的字典如:
| 字典名字 | 消费配置 | 含义 |
|---|---|---|
|
|
从远程 RBAC 模块中的读取 |
|
|
从远程全局字典配置中读取 |
加载 Assist 辅助数据的骨架代码如:
// 标准模块的书写方法(带企业信息的加载)
componentDidMount() {
Ex.yiStandard(this).then(Ux.pipe(this));
}
// 纯 Assist 数据加载
componentDidMount() {
Ex.yiAssist(this).then(Ux.ready).then(Ux.pipe(this))
}
注意此处的组件本身是经过了 @Ux.zero 的资源文件绑定过的,若是纯组件不具备加载 Assist 的条件(Form除外,新版表单和流程拥有内置的 assist 驱动流程)。
关于继承
Assist 辅助数据还有一种定义方式如:
{
"_assist": {
"user.departments": {
"uri": "/api/dept/by/sigma",
"inherit": "resource.departments"
},
"user.teams": {
"uri": "/api/team/by/sigma",
"inherit": "resource.teams"
},
"ajax.groups": {
"uri": "/api/group/by/sigma",
"inherit": true
}
}
}
上述辅助数据定义中,采用了 继承,数据继承的结构图如下:
上述结构图中可以知道,一般 父组件 的辅助数据来自两个方向:
-
自身的
props:一般辅助数据来自父组件 -
自身的
state:一般负数数据来自自身组件的加载
而这些数据会在往子组件传递时合并到子组件的 props 中,继承 功能点如下:父组件将字典 dict.name1 传入子组件中时,若子组件中出现了同名字典定义 dict.name2,此时这个字典就可以开启 继承 功能,继承有两个值:
-
true:子组件中的辅助数据和父组件辅助数据开启同名继承。
-
String:子组件中的辅助数据为父组件中的辅助数据开启别名模式(数据本身从父组件继承而来)
|
继承最大的好处是防止 组件嵌套 层次比较深时,同名字典出现了多次从远程加载的情况,正常模式下字典本身在一个 页面 级维持一份是最好的安排,但往往实际开发过程中不会这么简单。 |
批量配置
前边所有示例都是单字典模式,为了减少前后端交互,针对 TABULAR / CATEGORY 这两种字典类型前端提供了快速配置通道,使用此配置可以帮助 开发人员 执行批量配置,但这种配置模式仅针对 TABULAR / CATEGORY 有效。参考下边配置:
{
"_assist": {
"tabular": {
"uri": "/api/types/tabulars",
"method": "POST",
"magic": {
"$body": [
"norm.law.type",
"norm.law.policy"
]
},
"group": "type"
}
}
}
_assist 节点的子节点下边有两个特殊节点:
| 节点名 | 含义 |
|---|---|
|
列表类型的字典配置,只访问 |
|
树型的字典配置,只访问 |
此处您可以关注的配置是 group,此处的 group 表示您读取出来的所有字典是按什么属性(此处的 type)进行分组,分组之后,这样一个配置会往后端发送一次 Ajax 远程请求,但 type 有多少种最终就生成多少字典,简单说上述配置在底层会生成两个字典,底层等价于:
-- 实际执行的SQL
SELECT * FROM X_TABULAR WHERE `TYPE` IN ('norm.law.type', 'norm.law.policy');
-- 但是上边配置在前端会对应如下设置
-- 字典一:norm.law.type
SELECT * FROM X_TABULAR WHERE `TYPE` = 'norm.law.type' -- 等价SQL,实际不执行
-- 字典二:norm.law.policy
SELECT * FROM X_TABULAR WHERE `TYPE` = 'norm.law.policy' -- 等价SQL,实际不执行
简单说最终数据集会按照 type 进行分组,每组一个字典,而字典名称就是 type 的值。
synonym 同义语义
|
动态建模中,由于模型本身已经携带了属性别名,加上 |
synonym 同义语义一般在常用框架中都不会存在,开发人员完全可以使用 拷贝/复制 大法直接在 OOB 的基础上做一个新的模块,但是这样的代价是维护的成本比较高。synonym 语义处理的是 业务多态 的场景(目前版本主要做 呈现层 标签重命名):
此 语义 的优势在于应付 需求变更。它的诞生原因:
-
OOB 标准化模块一直处于开发和变动状态,如果使用传统的 直接拷贝 的方式,整个模块的版本会变得不容易维护,而每次开发完成之后您必须使用 拷贝 的方式将变更部分更新到新系统中,这样一旦出现大的基础模块的变动,您的整个系统升级会变得复杂——也可以理解
synonym是一种面向升级的语义。这种设计和 Zero Ui 中采取最初的 分发器 模式改成如今的一个单独的自动化指令:
ai sync是如出一辙,虽然这个命令目前也是使用的 拷贝,但 拷贝 这个动作是机器托管,自动分析,自动计算,最终类似自动化更新程序来更新框架,且更新部分禁止开发人员改动。 -
部分扩展的力度并没有达到要底层的表结构和模型发生变动,这种场景下拷贝完整的表、实体、模型无疑是一种 杀鸡用牛刀 的玩法,为了避免这种玩法,
synonym语义可以让您单纯从 业务语义 上穿一件外衣,而不去改动底层(接口可以使用统一授权模式,也可使用分离授权模式)。典型场景如:员工管理扩展出供应商员工管理、驻场员工管理、合作伙伴员工管理、内部员工管理,在目前的 OOB 模式下,基础的E_EMPLOYEE一直都岿然不动,只是单纯通过拓展的方式来实现:-
若没有任何新属性的需求,仅需将部分 展示层 重命名,如
员工工号 → 驻场员工编号,这种级别的变更直接用synonym同义语义是最快的。 -
若出现了新的属性的需求,那么可以采取 父主表 或 父从表 两种连接模式也可以达到新增属性的需求,但这种模式下,OOB 标准模块中的属性依旧依赖
synonym同义语义来装饰。
-
所以,同义语义既可以保证 已运行模块 的升级、变更、扩展流程,又可以兼容新模块的开发,还支持部分已存在的模块直接 积累/沉淀 成标准化模块,可谓一举三得。
表单配置
同义语义的表单配置位于 _form 节点之下:
{
"_form": {
"synonym": {
"name": "退款单标题",
"amount": "退款金额"
}
}
}
同义的表格示例(下边配置中不再解释)
| 属性 | OOB标准化模块 | 同义后标签 |
|---|---|---|
name |
单据标题 |
退款单标题 |
amount |
单据金额 |
退款金额 |
由于在目前版本的收款单、退款单两个核心对象中很多属性都是重复的,仅金额的正负不同,此时这两种模型出现了 同质化设计,于是 同义 语义就十分有作用,几乎“零成本”的方式就可以改造出两个新的基于标准化模块继承过来新模块(只是底层共享了表结构)。
列表配置
同义语义的列表配置位于 _grid 节点之下(参考 Ex.yiListSynonym 用法):
{
"_grid": {
"synonym": {
"title": "法规标题",
"description": "法规文档备注"
}
}
}
流程表单配置
同义语义的流程表单配置位于工作流定义的 UI_CONFIG 部分,通常如下:
{
"synonym": {
"phase": "销毁单状态",
"title": "销毁单标题",
"serial": "销毁单号"
}
}
编程配置
编程过程中处理起来就更加简单,直接搜索 Zero Ui 中的 $synonym 关键字就可以看到多数组件支持的同义语义部分,此处就不赘述,在后续实战章节注意拆解和讲解。
远程通信
Ajax基础
Zero UI中的Ajax调用一般可以直接使用 Ux.xxx 的API,基本使用如下:
import Ux from 'ux';
// 最终发送请求:GET /app/name/vie.app.zui
Ux.ajaxGet("/app/name/:name", {name:"vie.app.zui"})
上述代码中直接调用了 Ux.ajaxGet 方法发送 GET 请求,所有的Ajax类的API主要包含三个大类:
-
请求类:安全模式 / 非安全模式标准请求。
-
配置类:纯异步回调模式(古老的callback方式)。
-
响应类:和 Zero UI结合的各种不同响应模式相关。
请求类
请求类 API 主要设计和考虑维度如下:
-
是否执行Spring中带有服务名称(
serviceName)的微服务模型的API调用。 -
是否执行安全请求:
在 Zero 框架基础规范中,默认
/类型的API是公开类型的API,而带有/api前缀的API为标准API(即需安全认证的API),若客户端执行 安全请求,脚本会根据当前应用的认证模式(Basic, OAuth, Digest)为客户端请求生成Authorization头相关信息;不仅如此 Zero Framework 还支持 数字签名 功能,若同时在客户端和服务端启用了数字签名功能,签名模块 会自动为每个请求计算sig参数,默认使用算法HMAC-512(算法可同时在前后端配置)。 -
上传/下载类的请求都是基于 安全模式,其中分为
GET/POST两种不同的API。 -
请求类的签名统一为
(uri, params, options)或(service, uri, params, options),而返回值统一为Promise。
参考表格看看 请求类 API的详细信息:
| HTTP方法 | 安全模式 | 标准 | 微服务 | 含义 |
|---|---|---|---|---|
|
是 |
ajaxGet |
microGet |
标准GET请求 |
|
是 |
ajaxDownload |
GET下载 |
|
|
ajaxFetch |
microFetch |
公开GET请求 |
|
|
ajaxResource |
当前站点资源读取专用API,一般读取当前站点的HTML页做动态加载专用。 |
||
|
是 |
ajaxPost |
microPost |
标准POST请求 |
|
是 |
ajaxUpload |
标准上传请求 |
|
|
是 |
ajaxPull |
POST下载 |
|
|
ajaxPush |
microPush |
公开POST请求 |
|
|
是 |
ajaxPut |
microPut |
标准PUT请求 |
|
是 |
ajaxDelete |
microDelete |
标准DELETE请求 |
上述的API的常用参数表如下:
| 参数名 | 类型 | 含义 |
|---|---|---|
|
String |
「微服务」专用参数,用于表示服务名。 |
|
String |
请求专用路径,可使用类似 |
|
Object |
请求参数,通常是 |
|
Object |
请求头设置,可设置不同请求头(默认会计算部分请求头)。 |
配置类
配置类API会根据配置的方法执行分流操作(之前叫做 回调类,升级后语义有变化),通常配置类API都以 async 做方法前缀,现阶段所有配置类的异步API包含如下:
| 方法 | 含义 |
|---|---|
|
该方法通常用于 检查 函数,一般是检查数据存在或丢失专用的一个Ajax接口,这种接口只返回 |
|
该方法用于执行标准远程请求,远程请求正常则直接执行 |
|
该方法在上述提到的标准函数上执行了 配置封装,可支持Ajax的配置模式驱动远程通信请求。 |
|
该方法为图片加载专用方法,图片源可以是某个站点内图片,也可以是远程的二进制流转换的图片(手动 MIME)。 |
|
该方法为封装专用方法,在原始的Ajax配置类接口中封装了一层,封装类在部分地方起到了防御式效果,所以此方法属于新版正在使用的方法。 |
AJAX的标准配置如下(根据HTTP方法执行不同配置):
const V_ASYNC_FN = {
get: __AJX.ajaxGet,
post: __AJX.ajaxPost,
put: __AJX.ajaxPut,
fetch: __AJX.ajaxFetch,
push: __AJX.ajaxPush,
delete: __AJX.ajaxDelete
};
配置类API的两个核心参数此处有所讲究:
-
config 参数:
此参数通常格式如:
{ "uri": "xxx", "method": "xxx", "params.criteria": { }, "magic": { } }配置参数中必须说明的是两种不同的取参模式:
-
直接使用
params的方式提取参数,这种模式提取参数只支持criteria部分的 输入解析。 -
使用
magic的方式提取参数,这种模式会直接对参数执行 输入解析,且将解析结果注入到 QR 查询参数部分。
-
-
callback 参数:
callback作为回调配置,支持两种不同的格式:
-
Function 格式,直接使用编程的方式传入单结果回调,只传入
success时的回调。 -
Object 格式,这种格式会包含
success / failure两种回调,成功和失败分别走不同的回调。
-
响应类
响应类API主要用于后期处理,后期和前端界面交互渲染以简化回调效果信息,比如:
-
提交成功后,显示成功消息(
message类)。 -
提交成功后,弹出对话框提示结果(
Modal类)。 -
若提交失败,上述两种结果(红色)以失败的方式返回。
响应类API和其他类型不同,部分响应类API包含了 二阶 模式,二阶模式一般为 配置方式 专用,二阶的 编程方式 代码通常如下:
// 2阶使用如
const $opConfirm = (todo = {}, ref) => (reference) => (data = {}) => {
const request = {key: todo.key, data};
return Ex.I.todo(request, true)
// 二阶API弹出对话框提示
.then(Ux.ajax2Dialog(ref, buildConfig(ref, "confirmed"), true))
.then(response => Ex.rx(reference).close(response));
};
响应类API的清单如下
| 1阶函数 | 2阶函数 | 含义 |
|---|---|---|
|
x |
异常回调,解析错误信息专用,异常发生之后会执行 防重复提交 的表单还原。 |
|
|
正常回调,使用弹出框显示正常执行之后的回调效果。 |
|
|
消息模式,使用 |
x |
|
特殊二阶回调,返回值为 |
|
打印成功消息。 |
|
|
打印失败消息。 |
|
|
打印严重错误的基本消息。 |
最后结合源代码再讲一下回调配置,通常回调配置片段如下:
"_modal": {
"error": {
"empty": "对不起,请在权限组中添加权限信息!"
},
"success": {
"added": "恭喜,您已经成功添加了一条权限到当前权限集,您可以继续添加权限或关闭当前窗口!",
"saved": "恭喜,您已经成功更新了所选择的权限信息!"
}
}
上述片段中的配置通常位于 UI.json 的顶层,您可以直接调用 Ux.ajaxDialog 直接解析或提取配置,它有三个 根值
| 根键 | 含义 |
|---|---|
error |
红色异常信息,通常是错误信息,调 |
success |
绿色成功信息,调 |
confirm |
提示框( |
参数详解
前文讲解了前端专用的Ajax远程通信API,本章针对这些API的参数部分详细讲解,如此,开发人员就了解参数的 解析 / 配置 流程了。
uri
所有远程通信的第一个参数几乎都是 uri 或 service + uri 的格式,而 URI 格式处理过程会执行默认逻辑:
-
若存在
:param的路径参数,那么参数会一式两份,除了路径上的参数会被替换,而Query查询参数中也会包含,追加?param=xxx。 -
所有的查询参数在提交过程中都会执行
encoding的操作执行编码,后端会自动解码,以防止特殊字符、中文、标点的不合法性。
# 调用 Ux.ajaxGet("/api/user/:name", {
# name: "Lang",
# email: "silentbalanceyh@126.com
# })
GET /api/user/:name
# 参数params如下
{
"name": "Lang",
"email": "silentbalanceyh@126.com"
}
由于上边的 URI 带有 :name 的路径参数,所以此处会直接生成:
GET /api/user/Lang?name=Lang&email=....
|
有几种情况会直接将参数忽略:
当然您会觉得 |
默认参数
默认参数为系统配置的专用参数,若您使用了环境变量 Z_LANGUAGE,此参数会自动追加到您的 请求体 中( language=cn ),但请求体会包含两种格式:
-
直接请求格式
Ux.ajaxPost("/api/ui/ops",{control: key, type: "FORM"})如上边代码中的直接格式会将
params参数作为 Body 发送到远程,若自动追加就会变成如下 Body 格式:{ "control": "xxx", "type": "FORM", "language": "cn" } -
间接请求格式
间接请求格式一般使用的是路径参数格式,通常会将路径参数和 Body 区分开,如下:
Ux.ajaxPost(`${options[__Zn.Opt.AJAX_SEARCH_URI]}?QBE=:qbe`, { qbe: $qbe, $body: query });上述格式中默认参数会自动追加到
$body中而不是根数据结构上。
在部分特殊场景下如 QR 参数中,默认参数 不会被追加到请求中,以防止默认参数影响查询条件,虽然从 Zero Framework 中的语言部分可值,此条件不影响最终查询,在某些场景下此处的 language 参数也起到了限定作用。
禁用关键字
禁用关键字是 Zero Framework 独有的,由于 Zero 包含了查询参数 Qr 的数据结构如下:
{
"criteria":{},
"pager":{
"page": 1,
"size": 20
},
"sorter": [
"createdAt,DESC"
],
"projection": []
}
检查查询参数会以上述四个键为最高优先级,若包含了上述键作属性,Zero UI会将此请求判断成为 查询引擎 请求,部分前端组件会受到影响,所以在实际请求中需规避 criteria, projection, sorter, pager 关键字以防止请求参数混淆。
安全请求
Zero 中的安全请求通常使用 /api/ 路径,主要支持如下功能:
-
跨域安全请求
-
带
token的标准安全请求 -
带
xsrfToken的安全请求 -
数字签名功能
跨域安全请求直接在环境变量中配置:
Z_CORS_CREDENTIALS=include
Z_CORS_MODE=cors
上述环境变量控制了跨域处理中的选项 options,对应:
{
"mode": "cors",
"credentials": "include"
}
标准安全格式主要以计算 Authorization 的值为主,会根据现阶段的 安全模式 执行计算,目前支持 Basic, Digest, OAuth 三种,常用的两种如下表:
| 模式 | token | Authorization格式 |
|---|---|---|
Basic |
xxx |
|
OAuth |
xxx |
属性解析器
解析器基础
设计目的
Zero UI中的一个很大的亮点就是 属性解析器,属性解析器也可以称为配置解析器,您可以通过十分简洁的默认代码将属性解析成 Json Object 的方式来标准化配置格式。属性解析器的设计目的如下:
-
让开发人员更集中于配置中和业务直接相关的部分而 忽略配置的数据格式。
-
对 Json 格式的配置进行压缩,有了属性表达式之后原始配置信息会压缩到 20% 的体积,大大减少了开发人员对配置的实施量。
-
属性标准化:针对部分特殊属性可执行标准化操作,包括效果、文本、标签、图标等。
Zero UI中的属性解析器主要应用于如下场景(默认启用):
-
常用的表单字段,配合
AntD实现模型属性的配置化定制。 -
常用的列表列渲染,支持各种不同的列渲染结果。
-
窗口、请求等常用属性解析器,可提高开发人员开发这些定制组件的效率。
解析格式
前端配置的通用解析格式主要有如下三种:
-
(最简)纯字符串解析格式,如:
"title,标题,,,,placeholder=格式如:***公司,normalize=text:128" -
(高频)开发专用格式,如:
{ "metadata": "companyId,所属公司,,,aiTreeSelect,placeholder=(请选择所属公司)", "optionJsx.config.datum": "source=resource.companys,value=key,label=name", "optionJsx.config.tree": "text=name,parent=companyId", "optionJsx.config.selection": "mode=FULL", "optionConfig.rules": [ "required,请选择员工所属的公司!" ] }开发专用格式和其他两种格式的区别在于:
-
这种格式通常会有专用的
metadata属性作可解析部分,可解析部分 的格式和最简格式中的字符串格式是一致的。 -
这种格式支持属性的拉平语法,如示例中的
optionJsx.config.datum这种键值,Zero UI会将它自动解析。 -
这种格式除开
metadata之外,会带上部分附加配置(半Json结构),这些结构一般是为 复杂场景 而量身打造的,所以其作用主要是补充。
-
-
(完整)标准格式,如前文中格式展开之后如下:
{ "field": "companyId", "optionItem": { "label": "所属公司" }, "$render": "aiTreeSelect", "optionJsx":{ "placeholder": "(请选择所属公司)", "config":{ "datum": { "source": "resource.companys", "value": "key", "label": "name" }, "tree": { "text": "name", "parent": "companyId" }, "selection":{ "mode": "FULL" } } }, "optionConfig": { "rules": [ { "type": "required", "message": "请选择员工所属的公司!" } ] } }标准格式在整个配置表中是最规范的,如果使用程序生成对应的格式,推荐使用标准格式;标准格式会跳过属性解析部分,直接将格式中的JSON作为配置来执行处理,这种格式的缺陷是长度比较大(完整格式是最长的),开发人员在书写时略有不方便。
|
参考表格看看三种不同格式的使用场景,让开发人员更清楚其用法:
|
拉平语法
拉平语法是 Zero UI 中书写配置的另外一大亮点,其目的也是为了 压缩配置体积,参考如下配置:
{
"optionJsx":{
"style":{
"height":300
},
"config":{
"title":[
"left",
"right"
]
}
}
}
上述配置若是手工书写会写一堆 {} 或 [] 来展开完整配置,阅读比较规范,但体积(行数)偏高,有用的信息只有 1/3 左右,使用了拉平配置后其内容如下:
{
"optionJsx.style.height": 300,
"optionJsx.config.title": [
"left",
"right"
]
}
拉平配置中默认格式可采用不同方式拉平,如上述配置也可以写成(只要符合拉平原理的格式都是这种格式支持的,这点大大提高了开发人员书写配置的自由度):
{
"optionJsx":{
"style.height": 300,
"config.title": [
"left",
"right"
]
}
}
表达式
一般属性表达式的格式如:v0,v1,v2,v3,这种格式下,对应的 v0 表示索引为 0 的值,这种场景下会根据不同的 组件,其属性名有所区别,若某个一索引中无值,则需置空,若从某一个属性开始全部为空则可不用考虑,如:
# 如下边表达式 v2, v3 无值,但由于 v4=aiTextArea,所以需占位符
name,姓名,,,aiTextArea
# 下边格式 v2 开始全部为空
title,标题
若在使用过程中遇到了扩展属性,则要启用 $KV$ 占位符,$KV$ 占位符用于填充 原子解析器 中的原子属性,通常使用 key=value 的格式来执行解析,此处的 key=value 在后续的 原子解析器 章节中会有所说明。
:data-uri:
:table-caption!:
原子解析器($KV$)
表单/列表 部分解析器属于上层解析器,放到表单和列表章节中去处理,本章先从不同的视角讲讲特殊的几大类解析器。
原子属性表
原子解析器是Zero UI中针对特殊配置节点的 字符串 格式的解析器,主要用于书写字符串和 metadata 属性值,通常原子解析器格式如:attributeName=(value) 的格式。
|
原子属性并没有使用字典序的方式排列,相反是按使用场景排列的:表单、列表、按钮、全局。 |
| 属性名 | 配置节点 | 场景 | 含义 |
|---|---|---|---|
|
|
表单 |
此属性用于设置 输入限制 的不同模式,当前框架中支持不同的输入限制,解决的问题背景可以参考如下: - 多格式的表达式问题:https://gitee.com/silentbalanceyh/scaffold-zero/issues/I6W2BB |
|
|
表单 |
当某个字段处于只读状态时(
不论哪种模式造成的后果就是在只读状态下文字会变成 灰色,这样会导致部分只读的 阅读障碍,为了解决此问题才开启 |
|
(当前) |
表单 |
针对时间控件如 |
|
|
表单 |
后置插件,针对 |
|
|
表单 |
前置插件,针对 |
|
|
表单 |
前置文字,针对 |
|
|
表单 |
后置文字,针对 |
|
|
表单 |
输入之前的水印提示文字。 |
|
|
表单 |
针对时间、日期控件专用的格式化 |
|
|
表单 |
此属性主要针对 |
|
|
表单 |
「上传」组件中设置跨域模式必须的属性。 |
|
|
表单 |
「上传」组件显示文字自定义。 |
|
|
表单 |
「上传」设置组件种类,原生 |
|
|
表单 |
除了常用的录入型组件、下拉组件之外,大部分自定义组件也支持此属性,不同点在于开启此属性之后部分自定义组件会多一个 清空 按钮。 |
|
|
表单 |
此属性是多行文本专用属性,主要针对 |
|
|
表单 |
该属性是长度限制的原始属性,一般 Zero UI中使用 normalize 代替,主要原因如下:
|
|
|
表单 |
此属性是 |
|
|
表单 |
此属性是 |
|
|
表单 |
此属性是 |
|
|
表单 |
此属性是 |
|
|
表单 |
此属性用于组件中对组件本身执行 类型 识别专用。 |
|
|
表单 |
时间控件中时间格式专用属性,是否显示时间部分信息。 |
|
|
表单 |
控件中的模式:
|
|
|
表单 |
多选专用属性,当多选时使用 |
|
|
表单 |
自动聚焦属性,默认会将焦点聚焦到此控件。 |
|
|
表单 |
是否显示搜索框,此属性主要针对 |
|
|
表单 |
(状态)当前组件为 只读 时的专用属性。 |
|
|
表单 |
(状态)当前组件为 禁用 时的专用属性。 |
|
|
表单 |
针对表单中的 |
|
|
表单 |
此属性用于设置表单中 |
|
|
表单 |
此属性用于设置表单中 |
|
|
表单 |
影响当前组件布局的专用属性,对应 |
|
|
表单 |
影响当前组件布局的专用属性,对应 |
|
(当前) |
列表 |
此属性主要针对表格控件中的 |
|
(当前) |
按钮 |
此属性最早是针对 |
|
(当前) |
按钮 |
此属性最早是针对 |
|
(当前) |
按钮 |
「旧版」这个属性属于旧版本提交按钮专用属性,可设置提交按钮的提交相关内容,最终提交属性会触发 Form 相关的提交行为,生成按钮对应的提交行为配置。 |
|
|
按钮 |
新版用于配置按钮关闭行为的专用属性。 |
|
|
按钮 |
新版用于配置按钮回调行为的专用属性。 |
|
|
按钮 |
最新版用于直接配置远程 API 而无需额外的编程配置处理 |
|
(当前) |
— |
Ajax远程查询引擎排序参数 |
|
(当前) |
— |
分组专用属性,只要支持 |
|
(当前) |
— |
主键属性,若某个组件没有 |
|
(当前) |
— |
风格专用属性,设置 JSX 中专用属性 |
特殊场景
输入限制:normalize
输入限制是比较常用的一个属性,您可以直接使用 normalize 设置,现阶段 Zero UI 中支持的输入限制如下:
| 值 | 含义 | 格式 | 示例 |
|---|---|---|---|
decimal |
只录入浮点数 |
|
|
number |
只录入数值 |
|
|
id |
只录入账号和标识 |
|
|
integer |
只录入大于`0`的数 |
|
|
length |
录入不超过长度的数值。 |
|
|
text |
录入不超过长度的文本(中文算1的长度)。 |
|
|
upper |
录入不超过长度的大写。 |
|
|
实际场景示例如下:
{
"metadata": "name,银行名称,16,,,placeholder=请输入名称,normalize=text:40",
"optionConfig.rules": [
"required,请输入名称,名称不可为空!"
]
}
排序参数:sorter
排序参数一般在Ajax格式中使用(压缩版),用来处理查询引擎专用排序参数,参考如下示例:
{
"ajax": {
"metadata": "POST,/api/customer/search,1,10,sorter=name`ASC",
"params.criteria": {
"sigma": "PROP:app.sigma",
"type": "FIX:corporation",
"": "OPERATOR:AND"
}
}
}
上边配置中的 metadata 片段会直接被解析,而专用参数 sorter 的格式写法如下:
-
针对单个字段的排序
# 按 name 升序排列 sorter=name`ASC -
针对多个字段的排序
# 先按 name 升序排列、再按 code 降序排列。 sorter=name`ASC;code`DESC -
上述设置的解析结果(全格式)为:
[ "name,ASC" ]或
[ "name,ASC", "code,DESC" ]
输入水印变换
水印相关的属性如下:
-
incribe -
placeholder
这两个属性主要用于切换 只读 效果切换,它们支持一个特殊值 $CLEAR$,这个值会清除掉已设置好的水印文字,主要在 只读/禁用 两种状态切换时,三态表单中会有如下状态:
-
可编辑:水印文字需要继续显示在交互式组件中。
-
只读:若不显示水印文字(通常禁用),则需设置
$CLEAR$的效果,但若依旧要显示文字,则可能依赖incribe启动文字的呈现。
图标表达式
上述表格中还提到了图标表达式,它属于一个比较特殊的值(主要是 suffix 和 prefix),用于设置属性关联的图标信息(`<Icon/>`专用转换),最终会换成如下:
/*
* 直接将 suffix / prefix 的字符串转换成对象格式,此格式会注入内部实现 `<Icon/>` 的设置
* 此处的 type 表示 `<Icon type="xxxx"/>`,而新版会自动解析成所需的图标类型格式。
**/
optionJsx.suffix = {
type: value
}
组件解析器
本章节讲解 组件解析器,组件解析器位于 原子解析器 之上,它的解析通常根据场景有所区别,不同场景下 索引 对应的属性名不同。
窗口解析器
Zero UI中的窗口解析器主要分如下三种:
-
弹出窗口,对应
AntD中的<Modal/>组件。 -
抽屉窗口,对应
AntD中的<Drawer/>组件。 -
浮游窗口,对应
AntD中的<Popover/>组件。
窗口连接
Zero UI中的窗口连接是一种比较 怪异 的模式,这种模式拥有历史原因:
|
H5中现阶段已经支持表单内 |
它的原理图如下:
-
窗口外和窗口内部表单会形成一个父子级结构,二者使用了不同的
React组件来完成组装。 -
外窗口有两个核心变量(位于
state中):-
$visible:控制窗口的显示和隐藏,若触发函数rxClose则会直接关闭窗口,将此状态值设置成false。 -
$submitting:控制窗口外层按钮的 防重复提交,点击提交按钮之后不论是Ok还是Cancel在窗口级都会处于加载状态。
-
-
提交按钮主要分两层:
-
内层为表单内渲染的提交按钮(
display = none),该提交按钮带 id 属性(如id=$opSave),此按钮虽然对用户不可见,但属于 被连接点。 -
外层为窗口中的渲染按钮,一般是确认,属于 连接触发点,它内置会直接调用
Ux.connectId("$opSave")执行代码触发内置按钮的点击事件。 -
上述两个按钮之间的交互就是本章的 窗口连接。
-
-
最后
rxClose函数作为窗口关闭函数会从父组件(窗口)传入到子组件(表单)中,当表单提交完成后,可直接触发关闭,此时还会重设 防重复提交 状态。
弹出窗口
弹出窗口属性的定义如下:
[
"title",
"okText",
"cancelText",
"visible",
"width",
"maskClosable",
"onOk",
"component"
]
消费示例如下:
{
"_window": "配置信息,选择,关闭,false,800,true,$opSaveApi"
}
上述消费的配置最终会解析成如下:
{
"title": "配置信息",
"okText": "选择",
"cancelText": "关闭",
"visible": false,
"width": 800,
"maskClosable": true,
"onOk": () => Ux.connectId("$opSaveApi"),
"component": null
}
上述配置中的基础定义遵循 AntD 组件中的 <Modal/> 属性信息,详细属性可参考官方文档进行解读。由于 AntD 新版本使用了 open 代替 visible 属性,为了保证整个框架向前兼容型,所以此处依旧使用 visible 属性,Zero UI框架会自动执行转换。此处的 visible 属性需要如下解读:
-
上述
visible只是一个初始状态,通常弹出框的默认状态是visible = false的,但有会有类似 通知板 的情况(默认就是打开状态);实际执行过程中visible通常会和窗口组件的$visible状态值绑定到一起,并结合rxClose的关闭函数实现完整的窗口闭环。 -
onOk在此处配置的是连接点的id,前文已经讲过 窗口连接 相关知识点,此处的onOk最终会解析成一个 触发函数。
弹出窗口完整的属性表如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
当前窗口的标题显示文字,一般由外层配置。 |
1 |
|
确认按钮显示的文字,若没有配置则省略 确认按钮,某些场景下弹出窗口不依赖提交,直接提供关闭按钮即可。 |
2 |
|
取消按钮文字,若只有单独按钮可以考虑修正成 关闭。 |
3 |
|
窗口默认状态是显示还是隐藏。 |
4 |
|
窗口的宽度,宽度值一般是以 |
5 |
|
点击遮罩效果时是否允许关闭,默认一般点击遮罩不允许关闭(直接使用 |
6 |
|
连接点的按钮 |
7 |
|
默认 null,一般子元素会在编程过程中直接传入,就不会启用 |
|
编程过程中您可以使用下边代码执行 纯解析 流程:
|
抽屉窗口
抽屉窗口的属性定义如下:
[
"title",
"placement",
"width",
"closable",
"maskClosable",
"visible"
]
消费示例如下:
{
"window.extra.view": "视图管理,right,400,true,false",
}
上述消费的配置最终会解析成如下:
{
"title": "视图管理",
"placement": "right",
"width": 400,
"closable": true,
"maskClosable": false,
"visible": false
}
和 窗口配置 有区别的点在于抽屉窗口配置没有 确认 按钮,只包含了关闭按钮;其中还有一点在于 抽屉窗口 不存在窗口连接的功能,其内部不用调用 Ux.connectId 的API来同步两个不同按钮的状态。
抽屉窗口完整的属性表如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
窗口标题。 |
1 |
|
抽屉方向,主要包含`top, bottom, left, right`四个值。 |
2 |
|
抽屉窗口的宽度,一般`left, right`使用,如果`top, bottom`则该值表示高度。 |
3 |
|
是否支持`关闭`功能。 |
4 |
|
点击遮罩是否允许关闭。 |
5 |
|
该窗口默认显示值。 |
|
编程过程中您可以使用下边代码执行 纯解析 流程:
|
浮游窗口
浮游窗口的属性定义如下:
[
"title",
"placement",
"width",
"closable",
"visible"
]
消费示例如下:
{
"window.extra.column": "请选择您要显示的列,leftTop,640,true"
}
最终解析结果如下:
{
"title": "请选择您要显示的列",
"placement": "leftTop",
"width": 640,
"closable": true,
"visible": false
}
浮游窗口的完整属性表如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
title |
窗口标题。 |
1 |
placement |
浮游方向,有八个: |
2 |
width |
浮游窗口的宽度。 |
3 |
closable |
是否支持`关闭`功能。 |
5 |
visible |
该窗口默认显示值。 |
|
编程过程中您可以使用下边代码执行 纯解析 流程:
|
Ajax解析器
Ajax解析器是为了针对后端特殊场景执行请求核心解析,其中包括:
-
QR 查询引擎语法专用解析
-
参数解析(Qr参数、普通参数、Magic参数)
-
字典 / 分类 专用解析器
Ajax的属性定义如下:
[
"method",
"uri",
"params.pager.page",
"params.pager.size",
"$KV$"
]
该解析主要是针对 QR 查询引擎语法,配置部分写入如下:
{
"metadata": "POST,/api/user/search,1,10,sorter=updatedAt`DESC",
}
上述配置被解析之后会生成如下完整配置部分:
{
"method": "POST",
"uri": "/api/user/search",
"params":{
"pager": {
"page": 1,
"size": 10
},
"sorter": [
"updatedAt,DESC"
]
}
}
Ajax的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
Ajax使用的HTTP方法。 |
1 |
|
Ajax调用的远程URI路径。 |
2 |
|
分页功能中的页码,从`1`开始。 |
3 |
|
分页功能中的每页记录数,默认`10`。 |
4 |
|
专用键值对处理。 |
字段解析器(表单)
表单字段解析器属于 高频 解析器,且 $KV$ 中的内容比较丰富,参考 原子解析器 查看 表单 类的属性信息,表单解析器的属性定义如下:
[
"field",
"optionItem.label",
"span",
"optionJsx.style.width",
"render",
"$KV$"
]
在某些复杂场景中,通常会使用 metadata 来定义解析表达式(如添加验证规则、添加窗口配置等),表单解析器在此处就不举例了(源代码中这部分内容比较多),提供一个表单字段解析的示例:
{
"metadata": "companyId,所属公司,,,aiTreeSelect,placeholder=(请选择所属公司)",
"optionJsx.config.datum": "source=resource.companys,value=key,label=name",
"optionJsx.config.tree": "text=name,parent=companyId",
"optionJsx.config.selection": "mode=FULL",
"optionConfig.rules": [
"required,请选择员工所属的公司!"
]
}
表单字段的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
表单对应字段名。 |
1 |
|
表单字段前边的标题。 |
2 |
|
当前表单字段在Grid布局中宽度,最大宽度为24(善用 |
3 |
|
当前表单的相对宽度,一般为百分比。 |
4 |
|
该表单调用的渲染API,用于渲染不同组件专用。 |
5 |
|
专用键值对处理。 |
|
此处的顺序比较讲究,在某些大表单模式下,通常一个属性只需要使用 |
列解析器(列表)
列解析一般用于列表定义(使用了 AntD 中的 <Table/> 标签),此处可支持各种不同的列渲染,列解析器的属性定义如下:
[
"dataIndex",
"title",
"$render",
"sorter",
"$KV$"
]
列解析器的消费示例如下:
"columns": [
"name,权限名称",
"code,权限编码"
]
此处解析的属性结果就不枚举了,列的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
绑定的记录对应的属性名。 |
1 |
|
当前列的列标题。 |
2 |
|
列的渲染类型,该类型在列表章节详细解析。 |
3 |
|
是否打开列排序,如果打开则列中会启用排序功能。 |
4 |
|
专用键值对处理。 |
按钮解析器
按钮解析理论上只应该只有一种,由于 历史原因,此解析器如今已经拓展成如下四种:
-
连接按钮
-
提交按钮
-
组件按钮
-
命令按钮(特殊面板)
连接按钮
前文提到了 窗口连接 的基础概念,连接触发按钮 会单纯调用 Ux.connectId 去触发另外一个按钮点击事件。
连接按钮的属性定义如下:
[
"key",
"text",
"connectId",
"type",
"icon",
"disabledKey",
"$KV$"
]
一般这种按钮会位于外层组件中,如:
-
Tab页签的tabBarExtraContent中按钮连接内容(children)中的隐藏按钮,旧版使用<TabPanel/>,新版则直接使用items属性代替。 -
Card左右顶部按钮连接内部(children)中的隐藏按钮。
连接按钮由于需要 连接点 和 连接触发 两处的按钮双向状态同步,所以此处还需要同步 防重复提交,点击之后处于 loading 的状态,以下是 Card 中的部分片段:
"_page": {
"title": "新建申请",
"left": [
"btnOrderSave,提交,$opCreate,primary",
"btnOrderReset,重置,$opReset,default"
]
}
上述按钮的最终解析结果如下:
{
"key": "btnOrderSave",
"text": "提交",
"connectId": "$opCreate",
"type": "primary",
"icon": null,
"disabledKey": null,
"$KV$": null
}
连接按钮的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
当前按钮的`key`值(React专用)。 |
1 |
|
当前按钮显示的文字信息。 |
2 |
|
被连接的隐藏按钮的id。 |
3 |
|
该按钮的类型,对应Ant Design中的`<Button/>`对应的`type`属性。 |
4 |
|
该按钮显示的图标信息,对应`icon`属性。 |
5 |
|
该配置为一个遗留配置,用来控制按钮在什么场景中被动态禁用。 |
6 |
|
专用键值对处理。 |
提交按钮
提交按钮通常位于表单配置中,属于表单 内部专用 按钮,它和 AntD 直接产生绑定作用,实现表单的快速提交,简化开发人员开发提交函数。
提交按钮的属性定义如下:
[
"key",
"text",
"event",
"type",
"className",
"icon",
"$KV$"
]
其中最核心的配置是 event,它既可用于 编程模式 也可用于 配置模式,通常表单中的提交按钮配置如下:
[
{
"metadata": "$button",
"hidden": true,
"optionJsx.extension": [
"$opAdd,添加,SUBMIT,primary",
"$opReset,重置,RESET"
]
}
]
上述片段中以 $opAdd 为例,解析的最终结果如:
{
"key": "$opAdd",
"text": "添加",
"event": "SUBMIT",
"type": "primary",
"className": null,
"icon": null,
"$KV$": null
}
提交按钮的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
当前按钮的`key`值(React专用),表单中绑定触发函数也是依赖该key做函数名。 |
1 |
|
当前按钮显示的文字信息。 |
2 |
|
当前表单实现的标准化事件的名称,如`SUBMIT`或`RESET`等。 |
3 |
|
该按钮的类型,对应Ant Design中的`<Button/>`对应的`type`属性。 |
4 |
|
Zero中定义了不同颜色和风格的按钮专用className,该配置主要用于风格切换。 |
5 |
|
该按钮显示的图标信息,对应`icon`属性。 |
6 |
|
专用键值对处理。 |
组件按钮
组件按钮是Zero UI中的自定义组件 <DialogMenu/> / <DialogButton/> 专用,这两种组件可实现 按钮/菜单 内嵌子组件模式,点击模式下的弹框或窗口,和窗口配置配合之后,实现很复杂的交互模式。
组件按钮的属性定义如下:
[
"key",
"text",
"type",
"icon",
"confirm",
"$KV$"
]
组件按钮的消费配置如下:
{
"button": "itemCancel,撤销,,undo,若执行撤销,则这单据全部会变成无效,确认?,className=ux-spec"
}
上述配置最终会解析成:
{
"key": "itemCancel",
"text": "撤销",
"type": null, // 此处会使用 default 做默认值
"icon": "undo",
"confirm": "若执行撤销,则这单据全部会变成无效,确认?",
"$KV$": "className=ux-spec"
}
组件按钮的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
当前按钮的`key`值(React专用),表单中绑定触发函数也是依赖该key做函数名。 |
1 |
|
当前按钮显示的文字信息。 |
2 |
|
该按钮的类型,对应Ant Design中的`<Button/>`对应的`type`属性。 |
3 |
|
该按钮显示的图标信息,对应`icon`属性。 |
4 |
|
该按钮是否启用确认/取消的提示浮游窗口功能,打开选项后设置成浮游提示文字。 |
5 |
|
专用键值对处理。 |
|
上述配置中需要针对
|
命令按钮
命令按钮主要在 G6 的绘图板中使用,属于 专用按钮,这种按钮也可以扩展到其他场景,这种按钮的特殊点在于其内部触发模式不遵循 React 的基础原理,而是使用 H5 的模式在触发。
[
"key", // 事件专用 key,依靠这个绑定
"text", // 显示文字
"className", // 风格处理
"confirm", // confirm 窗口
"confirmPosition", // confirm 位置
"icon", // 图标信息
"tooltip", // tooltip 打开(打开过后文字放到 tooltip中)
"$KV$"
]
命令按钮解析配置属于 高级用法,主要操作为 Ux 中三个核心API:
-
opExtra,右上角附加命令按钮渲染专用。 -
opLink,链接命令按钮专用。 -
opCommand,标准命令按钮专用。
命令按钮不用绑定 onClick 函数,全部是外层传入内层触发,如下边配置
"_commands": [
"$opAutoSave,,ux-spec,确认打开?,left,undo"
]
上述按钮最终会解析成:
{
"key": "$opAutoSave",
"text": null,
"className": "ux-spec",
"confirm": "确认打开?",
"confirmPosition": "left",
"icon": "undo",
"tooltip": null,
"$KV$": null
}
命令按钮的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
当前按钮的`key`值(React专用),表单中绑定触发函数也是依赖该key做函数名。 |
1 |
|
当前按钮显示的文字信息。 |
2 |
|
Zero中定义了不同颜色和风格的按钮专用className,该配置主要用于风格切换。 |
3 |
|
该按钮是否启用确认/取消的提示浮游窗口功能,打开选项后设置成浮游提示文字。 |
4 |
|
浮游窗口的位置,该配置仅存在于命令模式的按钮。 |
5 |
|
该按钮显示的图标信息,对应`icon`属性。 |
6 |
|
该配置用于命令模式只配置图标型按钮(不显示文字),tooltip为鼠标移动到按钮上的提示文字。 |
7 |
|
专用键值对处理。 |
项解析
项解析存在于各种 复杂组件 内部,主要用于简化小规模的组件开发,如:
-
图标完整风格解析
<Icon/>,带色彩、大小、种类。 -
数据源过滤条件解析,自动过滤功能。
-
下拉、多选、单选项解析
图标解析
图标写法在 Zero UI 中可以简化,由于 历史原因 出现过几次比较大的变动,这些配置主要用于小图标修饰,标准配置定义如下:
[
"text",
"icon",
"iconStyle.fontSize",
"iconStyle.color",
"style.color",
"$KV$"
]
上述内容对应的源代码如:
<span>
<Icon/>
{文字部分}
</span>
消费示例如下:
"$mapping": {
"Pending": "未结算,exclamation-circle,16,#0a7bed",
"Finished": "已结算,check-circle,16,#268941",
"InValid": "无效,stop,16,#e22015"
}
上述示例最终会解析成如下配置:
{
"text": "未结算",
"icon": "exclamation-circle",
"iconStyle": {
"fontSize": 16,
"color": "#0a7bed"
},
"style":{
"color": null
}
}
图标解析的完整属性如下:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
text |
标签显示的文字。 |
1 |
icon |
图标类型,对应`<Icon/>`中的`type`属性。 |
2 |
iconStyle.fontSize |
控制图标大小。 |
3 |
iconStyle.color |
控制图标颜色。 |
4 |
style.color |
控制文字颜色。 |
5 |
|
专用键值对处理。 |
过滤条件
|
Zero UI中的组件有 字典关联 模式,这种模式通常会在页面初始化时从服务端远程读取字典所有信息作为核心数据源,再结合字典配置(
而过滤条件就是为数据源过滤量身打造,如一个下拉完整数据源中包含了 |
数据源配合下拉的属性定义如下:
[
"source",
"field",
"type",
"cond"
]
上述配置信息的消费片段如:
/*
* source = form 表示条件值的来源是 form 的 comment 字段,
* type = integer 则表示整数类型,类型有三
* - integer:整数
* - decimal:浮点数
* - 默认其他类型,如字符串
* 最终构成的查询条件为:
* condField = form中的整数字段comment
**/
form,comment,integer,condField
过滤条件配置比较特殊,不会生成最终解析的JSON格式,而是使用JS中的 Function 替代,它的完整属性表如:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
标识条件字段的值来源,可以是form,可以是state,可以是props。 |
1 |
|
标识来源处的某个字段名。 |
2 |
|
对于整数和浮点型必须做转换和设置,Zero Ui中所有判断都是`===`的三等号模式。 |
3 |
|
从字典中提取数据时的条件字段,最终形成`cond = value`进行过滤。 |
选项解析
选项解析主要服务于 单选、多选、下拉 组件,它用来描述每一个固定的项的绑定信息(通常下拉会包含值、文字两部分),选项的属性定义如下:
[
"key",
"label",
"style"
]
上述定义使用的范围比较广泛,也可以手工调用API来实现解析(快速解析项),配置消费段形如:
"optionJsx.config.items": [
"STANDARD,标准",
"VALID,无效"
]
上述消费段会被解析成如下结果:
"items": [
{
"key": "STANDARD",
"label": "标准",
"value": "STANDARD",
},
{
"key": "VALID",
"label": "无效",
"value": "VALID"
}
]
选项解析的完整属性如:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
选项键值,React专用。 |
1 |
|
选项呈现的文字信息(支持表达式格式)。 |
2 |
|
该选项的风格:文字颜色、大小等(保留,以前用过,现在很少用)。 |
容器项解析
容器想解析主要针对 <Tab/> 组件,属性定义如:
[
"tab",
"key",
"icon",
"$KV$"
]
当您使用多个页签来实现页签容器的配置时,则可直接配置对应的页签项而避免复杂配置:
// 不拉平模式
"_tabs": {
"defaultActiveKey": "keyPending",
"type": "card",
"items": [
"等待处理,keyPending",
"处理完成,keyFinished"
]
}
// 完全拉平模式(更简洁)
"_tabs": {
"defaultActiveKey": "keyPending",
"type": "card",
"items": "等待处理,keyPending;处理完成,keyFinished"
}
最终解析结果如下:
{
"items": [
{
"tab": "等待处理",
"key": "keyPending"
},
{
"tab": "处理完成",
"key": "keyFinished"
}
]
}
容器项的完整属性如:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
页签上显示的文字信息。 |
1 |
|
页签的键值,React专用。 |
2 |
|
页签对应的图标。 |
3 |
|
专用键值对处理。 |
输入解析器
输入解析器又称为 数据来源解析器,该解析器的使用场景如下:
-
表单初始化字段初始值配置。
-
组件的Ajax请求参数配置。
-
列表的查询参数设置。
参考如下配置:
{
"ajax": {
"metadata": "POST,/api/customer/search,1,10,sorter=name`ASC",
"params.criteria": {
"sigma": "x",
"type": "y",
"": true
}
}
}
上述配置中,此处生成的 伪SQL 条件如下:
sigma = 'x' AND type = 'y'
编程模式 下,此处的 x 和 y 可直接通过脚本制定,但若是配置模式(描述型),此处就要制定不同的数据来源来填充 sigma 和 type 才能生效,所以才有了 输入解析器 的存在价值,若使用输入解析器,上述配置可能会写成如下:
{
"ajax": {
"metadata": "POST,/api/customer/search,1,10,sorter=name`ASC",
"params.criteria": {
"sigma": "PROP:app.sigma",
"type": "FIX:corporation",
"": "OPERATOR:AND"
}
}
}
上述配置表示:
-
sigma的值来自于 React Component 中的 props 属性中,从$app中提取sigma的值。 -
type的值为固定值,设置为corporation的固定字符串。 -
两个条件之间的条件为
AND连接符。
所以输入解析器通常会使用 <SOURCE>:<EXPRESSION> 的格式执行相关定义,下边章节一一讲解所有的可解析数据源头。
NUMBER
在 JavaScript 中的数值类型只有 Number,所以数据源中处理数值时需依赖此输入解析器,不可以使用 "0" 的字符串方式表示数值,它的示例片段为:
{
"person": "NUMBER:1",
"price": "NUMBER:0"
}
BOOL
布尔值的用法几乎和 NUMBER 一致,直接将参数转换成 Boolean 的数据类型,防止直接使用 "false" 这种字符串字面量方式,示例片段如下:
{
"active": "BOOL:true"
}
|
JavaScript 是弱类型语言,通常在执行类型处理时不会直接转换成合法类型来对待,而后端的数据类型是 严格 的,所以很多场景下需要将前端的 JavaScript 中的字符串字面量转换成带有 强类型 语言特征的值才能正确和后端交互,这种场景下 |
OPERATOR
此输入解析器只针对 QR 查询引擎生效,用于描述当前层中条件连接符,而根据 Zero 中的查询引擎规范,条件连接符使用空字符串作字段名,所以示例如下:
{
"params.criteria": {
"sigma": "PROP:app.sigma",
"type": "FIX:corporation",
"": "OPERATOR:AND"
}
}
注意在 QR 查询语法中,如果不设置连接符,那么默认使用 OR 的连接符来连接查询条件。
FIX
此输入解析器为固定值解析器,后续内容就是设置的值,又称为 常量值解析器,您的配置中写什么就是什么,示例如下:
{
"value": "FIX:student"
}
上述表达式中 value 的值会被直接解析成 value = student。
DELAY
这种格式很特殊( 延迟渲染 ),在 Ant Design 的表单中第一次 render() 方法调用表单时旺旺没有任何初始化操作,这种模式下可能需要启用延迟加载,延迟加载有可能是 componentDidMount 方法中直接从远程读取,也可能是第一次初始化之后从 componentDidUpdate 方法从远程读取,这种类型的延迟操作都依赖这种方式的输入源。
这种模式下延迟字段会引起 Ajax 延迟远程加载后编程数据发送出来。
ENUM
枚举格式 输入解析器,这种格式通常用于多值输入源的情况,示例如下:
{
"status,i": "ENUM:Requested`Pending`Finished"
}
上述枚举类型最终会解析成如下结构的数据:
{
"status,i": [
"Requested",
"Pending",
"Finished"
]
}
此处注意枚举值之间的格式是使用的 ` 符号,英文逗号 在解析结果中包含特殊的解析含义,因为此原因枚举值和值之间的间隔符使用了此符号。
FORM
特殊输入来源:数值来源于 Ant Design 中的表单,一般初始化过程中不会使用此 输入解析器,初始化过程中由于表单本身可能未加载完成,所以不能使用这种 输入解析器,所以此解析器通常用于表单交互过程,如级联下拉、级联过滤等。示例如下:
{
"metadata": "floorId,楼层,14,,aiSelect,placeholder=(请选择层信息)",
"optionJsx.config.datum": "source=floors,key=key,label=name",
"optionJsx.config.cascade": {
"source": "tentId",
"target": "FORM:tentId"
}
}
上述配置中配置了级联过滤,使用 tentId = 表单选择数据 对当前下拉执行过滤。
DAUTM / UNIQUE
这两种类型的 输入解析器 比较接近,也属于常使用的 输入解析器,它会定义一个字典作为数据源,如一个配置项的状态:
| 值 | 显示文字 |
|---|---|
|
运行中 |
|
等待审批 |
|
在建 |
假设此处配置的字典名称为 ci.status(对应到 source 配置),那么本章的 输入解析器 如下:
// 格式一:直接拉取数组的 Array
DATUM:source=ci.status
// 格式二:根据条件对数组执行过滤
DATUM:source=ci.status,code=(xxx)
此处的 xxx 是 嵌套表达式,这种模式只有在特定场景会使用,此处就不累赘了,UNIQUE 输入解析器 是 DATUM 的一种变体,用于读取唯一记录集:
{
"status": "UNIQUE:ci.status,key,code=FIX:RUNNING"
}
上述结构中消费 ci.status 的内部逻辑如下图:
PROP / STATE
此输入源很简单,直接从 React 组件的属性或状态中提取相关值,由于 Zero UI 存在专用数据模型,所以在提取数据时会有一定的规则。示例如下:
{
"sigma": "PROP:app.sigma"
}
|
此数据规则对所有类似
|
ROUTE
此输入源直接从 React Router 构造的 $router 变量中提取和路由相关的数据,示例如:
{
"params": {
"type": "ROUTE:type"
}
}
内部会调用 $router._("type") 来提取参数,而路由参数会包含如下两种:
| 类型 | URI格式 | 含义 |
|---|---|---|
路径参数 |
|
浏览器访问 |
查询参数 |
|
此时直接解析 |
USER
此输入源会从当前登录用户中提取数据信息,切支持 嵌套对象 提取。示例如:
直接提取
{
"companyId": "USER:companyId"
}
嵌套提取
{
"companyId": "USER:company.key"
}
上述第二个示例中会从 company = {} 去提取二级嵌套属性的值来执行赋值。
表单配置
表单开发
Zero UI中的表单开发主要以配置为主,而在开发过程中可直接使用模板代码进行开发,开发人员真正需开发的部分:
-
开发
Op.js针对表单中的提交部分执行函数开发。 -
开发
UI.js的入口表单开发。
表单的基础配置以两部分内容为主。
-
配置加载:直接从
UI.json中提取_form的配置信息,或从远程访问读取JSON部分的数据构造表单基础配置。 -
渲染标准化:调用
Ex.yoXxx系列方法对表单配置执行标准化处理,最终传入ExForm组件中执行表单扩展处理。
基础Json
{
"_form": {
"layout": "??",
"className": "??",
"window": "??",
"columns": "??",
"ui": [
[]
],
"assist": {},
"hidden": [],
"initial": {},
"rule": {},
"op": {},
"io": {},
"metadata": {},
"segment": {},
"modal": {},
"rowConfig": {},
"rowClass": {}
}
}
上述结构是目前比较常用的一个表单配置的基本结构,也是开发人员必须掌握的完整表单配置结构信息,这份结构基于代码梳理,部分的变化结构并没有在文档中指出,后续可持续更新。
布局属性
Zero UI 中的表单开发使用的是 AntD 中的 <Form/> 标签,它的布局并没有使用官方的 流模式,而使用了经典的 Grid 布局模式(24列),控制表单布局的主要有如下属性:
-
window:选择布局类型,Zero UI中提供的布局类型的值有如下:值 类型 含义 1标准布局
(默认值可不填写)常用的表单标准布局
1.1增强型标准布局
对字段的标签文字进行了深度考虑之后更符合复杂表单的核心增强型布局,某些场景下比
window=1的布局更好用。0.159:15布局
左侧带有很宽页边距的布局模式,一般是
1列字段的表单布局专用,此处9:15表示一个输入字段中的 标签:输入控件 的横向布局信息。0.169:15宽文布局
增强型
0.15的布局模式,针对某个字段 文字比较多 (如七个字、八个字)的专用布局,一般0.15时候标签文字不超过四个的布局方式。0.179:15子表单布局
增强型
0.15的布局模式,若此表单中包含了 子表单,那么这种布局模式更适合。0.21Word布局
这种布局模式属于之前认证评价系统专用布局,表单本身就是一个Word文档,格式也是参考Word文档的格式执行深度定制。
0.5两列标准布局
常用的
2列字段的标准布局,通常两列是12:12的方式。0.51两列变种布局
类似
1 → 1.1的变体一样,这种类型两列布局可以解决 文字较多 的场景。0.10110:14布局
新布局模式,标签:输入控件 横向比例 10:14
0.12112:12布局
新布局模式,标签:输入控件 横向比例 12:12
-0.3抽屉搜索表单
右侧抽屉拉出来之后的表单布局模式。
-0.5高级搜索表单
点击了 高级搜索 之后的布局方式。
上述布局设置中参考如下注意事项:
-
若要扩展新的布局,您可以直接更改
src/zion/variant-layout/中新增布局定义文件、扩展新值即可,键使用浮点数。 -
一般在表单布局中,负数 表示过滤搜索表单布局,正数 表示提交型表单的布局,大于
1表示高频布局,小余1则表示特殊变体。
布局本身设计如此复杂也是有 历史原因 的,在早期的
AntD和新版本的AntD中,标签对齐都是直接在编程代码中手工设置,这样的模式会导致大量布局前端的重复代码,且上下字段对齐特别是标签对齐相对麻烦,所以才有了Zero UI中的布局自动计算,布局解决的核心问题是在 字段占用 Grid 布局中的列不同但上下标签依旧是对齐的,这样的解决方式虽然在设置值时会略微复杂,但可以解决超过300个字段的大表单的上下布局问题。 -
-
columns:选择此布局类型中每一行默认容纳的字段数量。该值相对比较简单,牵涉到每一列的
span的自动计算,Zero UI会根据window和columns两个值自动计算单个字段的span属性,让Grid布局更具智能化,某些标准模式下几乎不需要设置span就可以完成上下完整对齐。值 含义 1
单列表单,每一行只有一个字段,标准模式下:
span=24。2
双列表单,每一行有两个字段,注
0.5 / 0.51只支持columns=2的情况,标准模式下:span=12。3
三列表单,每一行三个字段,标准模式下:
span=8。4
四列表单,每一行四个字段,标准模式下:
span=6。 -
layout:对应AntD中的属性值,默认是inline,可支持的值包括:horizontal、vertical、inline。
布局除开上述三个属性以外,还有针对单行的处理属性:rowConfig,在 rowConfig 中您可以针对某一个行(索引为键值)的布局执行修正效果,造成模式和模式之前横向的变体,这样其布局就可以突破单个布局的局限性,如 1 和 0.15 的混用时,可能依赖调整 rowConfig 来达到 对齐 的效果,若没有此配置那么 window 一旦指定表单就会被固化下来,而在更多复杂场景时 布局固化 是一个十分可怕的事。
|
关于布局有一个可能困惑开发人员的东西,就是表单渲染中的 此处解释下
上述模式中既可控制到行,又可以控制到列,有了 行列 配置之后,您可以很容易对当前表单中的组件进行定位,此处解读
上述布局文件中的左值就是 |
风格属性
风格属性主要有如下两个属性:
-
className:当前表单的专用属性,默认值ux_form,若您指定了className之后,那么指定的值将会直接追加和覆盖原始的ux_form(原始风格依旧生效)。 -
rowClass:针对表单单行的属性设置,您可以在一个完整的基于Grid的表单中设置某些行特殊的风格信息,如交叉行、反色单行、协变宽高等。
数据处理
数据处理属性主要包含如下属性:
-
assist:辅助数据(字典数据)表单内加载流程。表单内若某些字段绑定了字典信息来构造 下拉、多选、单选 等相关信息,这种场景下表单本身依赖字典数据来构造 可操作源,而辅助数据的绑定存在两个不同版本的跨越:
-
外部源
_assist:此配置位于页面级,不在表单内部,表单内部不用设置任何assist的属性,依旧可以使用字典数据绑定。 -
内部源
assist:此配置位于表单级,在表单内部初始化流程中会被触发,配置格式是一致的。
外部源的模式比较适合 开发模式,而内部源多用于 配置模式。
-
-
initial:初始化数据初始化数据一般用于添加类
mode=ADD表单,您可以直接在initial中根据所需对字段执行添加表单的默认值配置,配置片段如下:{ "initial": { "active": "BOOL:true", "appId": "PROP:app.key", "type": "FIX:ftp", "protocol": "ftp", "port": "21", "path": "/" } }从配置格式可以知道,表单中的初始化数据是支持 输入属性解析 功能的,若您设置的字段值带有
PREFIX:的前缀,那么此属性会使用 输入属性解析 功能从不同的数据源来填充初始值。 -
rule:延迟初始化如果系统中包含了
linker类型的字段影响连接,那么通常在 Zero UI中使用的是fieldName / fieldId的模式进行双字段渲染,然后填充对应渲染的数据,可是会出现一种情况:若此处的 fieldName 是另外一个字段 的数据,并非和fieldId绑定的数据那么应该如何操作?此时您可以自定义新的数据加载流程,此加载流程在rule中设置,参考如下片段:{ "_form": { "rule": { "parentName": { "seeking": { "uri": "/api/x-category/:key", "magic": { "module": "fm.subject" } }, "linker": { "owner": "owner" } } } } }简单讲解下上述配置来理解
rule属性的延迟初始化效果:-
上述表单中
parentName属性名并非对应的是parentId,此种情况下依赖此处定义的规则在用户读取表单数据时多执行一次数据提取流程。 -
不仅如此,这种数据规则可访问远程的某个接口将抓取的数据通过 Zero UI中的
linker机制默认填充各种数据字段,如此处填充的owner → owner,此处可设置更复杂的延迟初始化规则。
-
-
io:输入/输出规则(非异步)输入/输出规则配置属于 高级话题 的内容,现阶段通常用于流程表单中做复杂提交,配置片段参考如下:
{ "io": { "writer": { "record": { "inSource": "linkageAsset", "inPath": "targetData", "outType": "ARRAY" } } } }-
输入 表示表单加载过程中的数据初始化流程。
-
输出 表示表单提交过程中的数据收集流程。
此部分内容在后续实战中逐一讲解,一般使用场景如下:
-
字段数据格式和提交到远程数据格式不完全对齐的情况下,依赖
io规则补充、追加、转换部分字段数据。 -
针对数据本身 Array / Object 两种不同数据格式之间的切换,以适配提交数据。
-
您可以将
io规则理解成表单生命周期中的AOP行为,可自定义 加载、交互、提交 等不同生命周期的表单数据行为。
-
字段属性
字段属性在 Zero UI 中包含两个:
-
ui:针对可见字段属性的定义。此属性的数据结构是一个二维数组:
[ [ ], [ ] ]二维数组描述的是
Grid布局的基本骨架:-
一维表示的是当前表单有多少行,
rowConfig / rowClass就是作用于一维配置。 -
二维表示的是某一行内的字段信息,由于是一个 Array 结构,所以有多少
{}单元格配置元素当前行就包含多少字段。
-
-
hidden:不可见字段的属性定义,hidden不参与布局。
安全属性
安全控制关注的属性是 op,此属性描述了当前表单中操作的 安全定义,现阶段的版本还没完全实现表单的细粒度控制,只要按钮可以呈现那么对用户而言就可以触发表单的提交,而 op 属性可直接实现和 S_ACTION 的绑定关系,这样绑定之后会造成用户在点击提交时可能会触发 403 异常,简单说就是:您可以看到这个表单,但是当你触发提交操作时,无权限访问接口。
回调属性
回调属性和Ajax中的回调属性如出一辙,定义的是表单提交完成之后的回调行为:
-
弹出成功弹窗提示操作成功。
-
显示成功消息提示。
回调属性的配置片段如下:
{
"modal": {
"success": {
"open": "您好,您的流程申请已成功提交,申请单号 :serial,请等待审批。",
"draft": "您好,您的流程申请已成功保存为草稿!单号为 :serial。"
}
}
}
|
回调属性是新版提交按钮的配置,在新版按钮配置中,您可以设置 原子属性:
|
骨架代码
若您配置了上述的表单之后,可直接书写骨架代码来完成表单的整体组件开发。
源代码 UI.js
import React from 'react';
import Ux from 'ux';
import Ex from 'ex';
import {ExForm} from 'ei';
import Op from './Op';
@Ux.zero(Ux.rxEtat(require('../Cab'))
.cab("UI.Add")
.to()
)
class Component extends React.PureComponent {
render() {
const form = Ex.yoForm(this, null);
/*
* 如果是更新,上述代码改成
* const {$inited = {}} = this.props;
* const form = Ex.yoForm(this, null, $inited);
*/
return (
<ExForm {...form} $height={"300px"}
$op={Op.actions}/>
);
}
}
export default Component;
针对上述代码说明几点:
-
一般表单开发会使用
ei库中的ExForm组件,此组件还会帮助您完成各种智能模式处理(已在生产环境验证很高频的用法,减少代码量)。 -
表单和资源文件绑定之后,会直接从
cab/cn/目录下抓取 名空间 对应的JSON配置文件。 -
此处的行为模式主要绑定
Op.js中的actions变量,此变量定义在下边有说明。
|
Zero UI中不推荐将文本呈现放到 JS 文件中,通常一个组件会包含两部分:
不论是前端还是后端都可以直接在配置提取过程中读取不同的 语言资源文件,这样的模式下会保证您的界面实现最大限度的灵活定制,若想要从 中文 切换到 英文,只需要更改资源文件信息即可,不用对源代码进行任何调整。 |
操作代码 Op.js
import Ex from 'ex';
const $opAdd = (reference) => params => Ex.form(reference).add(params, {
uri: "/api/role",
dialog: "added",
});
const $opSave = (reference) =>
params => Ex.form(reference).save(params, {
uri: "/api/role/:key",
dialog: "saved"
});
const $opDelete = (reference) =>
params => Ex.form(reference).remove(params, {
uri: "/api/role/:key",
dialog: "removed"
});
const $opFilter = (reference) =>
params => Ex.form(reference).filter(params);
export default {
actions: {
$opAdd,
$opSave,
$opDelete,
$opFilter
}
}
上述代码是最简单的角色管理,由于没有任何自定义逻辑,所以此处可直接使用 Ex.form(reference) 的方式实现相关提交,而配置使用了标准化按钮配置:
| 按钮ID | 含义 |
|---|---|
|
添加按钮专用表单函数, |
|
更新按钮专用表单函数, |
|
删除按钮专用表单函数。 |
|
查询表单专用函数,右侧抽屉搜索框专用。 |
最后需要注意的一点是此处的函数本身具有一定的基本规范
-
此处的函数定义的是一个 二阶函数,函数签名如下
const $opXxx = (reference) => (params) => { }-
reference是和操作绑定的外层组件的引用,需要开发人员注意引入外层组件之后的层级关系,可通过Ux.onReference的方式精确捕捉所需组件。 -
params是 Ant Design 中的表单提交之后的数据。
-
-
此处的操作函数返回一个
Promise,返回Proimse的原因很简单:同步/异步 统一,而且往往这种类型的提交都会和后端互动,所以使用 异步 比同步的实用性更强。 -
Ex.form的表单对象引入了默认的 防重复提交、默认回调、异常验证、异常回调、规则转换 等综合性功能,除非您十分了解,否则只能自己老老实实书写自己的函数,如(自定义流程):const $opCreate = (reference) => (params) => { const request = Fn.ioRequest(params); let category = {}; if (request.grouped) { category = Ux.elementUniqueDatum(reference, "preorder.category", "code", "Company"); } else { category = Ux.elementUniqueDatum(reference, "preorder.category", "code", "Personal"); } if (category) { request.category = category.key; } return Ux.ajaxPost("/api/order/standard/submit", request) .then(data => Ux.ajaxDialog(reference, { data, key: "submitted", redux: true, })) .then(response => Ux.formReset(reference, [], response)); };由于此处没有使用
Ex.form的表单对象,所以回调中的Ux.ajaxDialog以及执行完成之后的表单重置Ux.formReset都是必须的。
按照本章的教程,基本开发人员只需要 拷贝 骨架代码,然后书写对应的行为函数( Function )就可以完成表单部分的开发,且不需要书写太多的表单规则或逻辑规则,接下来看看表单中常用的 字段配置。
:data-uri:
:table-caption!:
高级话题
本章节难度比较大,后续在开放 开发中心 时再一一补充,完成教程书写,现阶段开发人员可暂时略过。
数据转换
此部分内容为实验性版本,现阶段除了流程表单中存在 io 配置,其他位置的配置并没有出现,还存在待改进以及不稳定的情况存在。但 io 这个设计会延续,此设计方便开发人员直接配置 页面流,在读写( input / output )两个生命周期内注入 规则、插件、函数 来完成数据转换相关的定制。
Zero 表单配置新版本中中加了特殊配置来执行数据的进出控制,主要处理表单的 加载和提交 的生命周期,让您可以针对表单的数据流程执行细粒度控制,先参考下边两段配置:
io
{
"io": {
"writer": {
"record": {
"inSource": "linkageAsset",
"inPath": "targetData",
"outType": "ARRAY"
}
}
}
}
transform(将被 reader 代替)
此部分位于代码:src/utter/channel.__.v.yo.transformer.js 源码。
{
"transform": {
"record@file": {
"type": "FILE",
"field": "record@fileKey",
"fieldName": "record@name"
},
"record@sizeUi": {
"type": "SIZE",
"field": "record@size"
}
}
}
后期的基本设想是直接使用 io 配置完成所有的读写流程,参考 io 在表单生命周期中存在的位置:
writer
writer 中记录了每一个字段的基础配置,此处配置的数据结构如下:
| 配置项 | 含义 |
|---|---|
|
固定值和别名:
|
|
当前配置属性采集的数据源属性,此处由于是提交内操作,所以源头默认为当前表单已提交的数据。 |
|
条件检查配置项,它所定义的条件满足的情况下才能触发当前属性的 |
|
从当前采集数据的数据源中提取路径下的内容,此属性支持 表达式,前端会根据 |
|
转换之后的数据类型
|
此处的 writer 的执行流程如:
所以上述 writer 的执行流程如:
-
从表单提交数据中提取
linkageAsset属性,此处属性数据类型是[]数组类型。 -
跳过
inPre步骤检查。 -
从提取到的属性中抓取
targetData部分的值-
如果提取源是
[]类型,那么此处做的是 投影提取。 -
如果提取源是
{}类型,那么直接提取key = targetData部分的值。
-
-
最终输出是
ARRAY,会构造[]的输出类型。
io 的全称是 input / output,意为表单生命周期中 加载 和 提交 两个生命周期,有了此处的配置,表单本身的行为有了很大的扩展空间。
reader
(暂时还未使用,教程滞后)。 :data-uri: :table-caption!:
表单组合
前文中提到的是 _form 配置节点,除了此节点以外,表单配置还支持 按行组合 的方式对表单碎片 从上到下 的布局模式,这种模式属于 表单组合(参考 Ex.yoForm 函数):
|
每一个表单都遵循本章的表单结构,系统会将
表单配置中就是使用了 |
表单片段完整如:
| 配置项 | 编码 | 含义 |
|---|---|---|
|
|
(编程模式) |
|
|
(上半部分) |
|
|
(上半部分) |
|
|
(上半部分) |
|
|
(主表单) |
|
|
(主表单) |
|
|
(主表单) |
|
|
(工作流) |
|
|
(下半部分) |
|
|
(下半部分) |
|
|
(下半部分) |
参考下边的表单组合原理图理解此处的表单合并过程:
从上述原理图解析:
-
编程模式直接扩展通常使用
additional中的配置,优先级比较高,除此之外,若是自定义组件,编程模式还可以:-
父组件更改配置之后传入子组件中填充
$options变量,上层编程配置。 -
当前组件更改状态之后更新
$formS变量( Server Form ),本层编程配置。
-
-
标准处理中
$formS的含义为Server Form,即通常用于从远程 Ajax 接口拉取表单配置,服务端三种配置一般如:-
动态配置:这种模式不启用 表单组合 功能,纯动态配置,上边原理图会失效。
-
组合配置:这种模式中通常会拉取远程
X_MODULE中的配置并执行解析,最终会将服务端的表单配置存储到$formS变量中。 -
工作流:这种配置只有一个 扩展,目前是工作流专用,和工作流中的节点绑定的专用配置。
-
-
顺序调整:上边提供的编排是 Zero Ui 提供的默认表单组合配置,您也可以在编程过程中更改
formRules根据 编码 更改您想要的表单片段。 -
除 工作流 之外,所有的表单源都提供了:上、中、下 三种模式,再结合:编程、前端配置、后端配置 三种情况,实际形成了一个表单组合的九宫格,这种模式下已经可以满足大部分表单的组合流程了。
|
表单组合 这种模式只适用于行交换,简单说不可以做单行中的列切换,如某一行有: 若对表单执行切分,原子级 的单元是属性(字段),而在 Zero Ui 中由于有 Grid 布局,又多了一级:行级,表单组合 实际在 行级 之上为表单又创建了一级:区域级,这样设计的目的实际是简化开发和配置工作量,下边两种场景不适合 表单组合:
表单组合 是 Zero Ui 提供的兼容了纯动态和纯编程两种模式的一种折中形态,折中形态一方面可以减少编程量和配置量,另外一方面表单本身可以使用“搭积木”的方式来完成,表单内置实现了模块化布局。 |
表单碎片
表单碎片 和表单组合一样,同样是开发表单布局使用的内容,现阶段只用于 工作流管理,教程暂时不梳理,后续版本落地成型后再追加到白皮书中(目前版本比较脆)。
字段配置
字段配置是表单配置中的重头戏,参考前文提到的字段解析器,实际字段配置中会包含如下特殊的属性:
| 配置属性 | 含义 |
|---|---|
|
当前字段的字段名,有两种配置模式
|
|
此属性服务于早期 |
|
此属性主要对应到 |
|
此属性为输入控件专用属性,对应到真正的 |
|
当前字段是否时间格式,理论上此处不应该如此设置,但由于 |
|
当前字段在 |
表单的字段配置主要位于:
{
"ui": [
[
"字段定义",
{
"comment": "字段定义"
}
]
]
}
optionConfig.rules 会在单独的 验证规则 章节说明,此处就不累赘。
-
本章只讲解各种字段基础配置,若找不到示例代码可能由于字段本身不常用,这种场景教程不会完全覆盖。
-
标题中带
(A)标记的是AntD的原生组件。 -
每个章节中的 特殊配置 是根据
AntD和 Zero UI 结合的实用性配置,和AntD不同的点在于 Zero UI 几乎全程是配置驱动。 -
部分复杂的 高频 使用组件我会在教程中附上对应截图,让开发人员对 Zero UI 中的表单类 交互式组件 有个感性的认识,截图由零点科技有限公司(使用Zero的友人)提供。
aiInput (A)
最简单的文本渲染,对应 AntD 中的 <Input/> 组件,也是默认值(即不配置也可),配置如下:
{
"metadata":"name,名称,14,,,placeholder=20个中文字符,normalize=text:40",
"optionConfig.rules":[
"required,请输入名称,名称不可为空!",
{
"validator": "existing",
"message": "对不起,名称重复!",
"config": {
"uri": "/api/role/existing",
"method": "POST",
"params": {
"sigma":"PROP:app.sigma"
}
}
}
]
}
上述代码取自 角色管理,先忽略 optionConfig.rules 部分的验证规则配置,若去掉验证规则此处的配置有如下写法(注意此处的 [] 是第二个维度,并非最上层维度):
写法一
[
"name,名称,14,,,placeholder=20个中文字符,normalize=text:40"
]
写法二
[
{
"metadata": "name,名称,14,,,placeholder=20个中文字符,normalize=text:40"
}
]
一般情况若不开启验证规则而 原子解析器 又可直接生效的场景中不采用第二种 metadata 的写法,第一种写法更省事,且注意所有 $KV$ 部分必须在定义的表单字段解析器格式之后,从索引 5 开始书写 key=value 的 原子解析 模式。上述配置中若没有后续的 原子解析 信息可直接书写成:"name,名称,14"。由于 aiInput 是默认值,所以此处带 render 的写法应该是:"name,名称,14,,aiInput"。上述配置最终解析的完整配置如( 后续配置 不再开放完整格式,大家自行阅读。):
{
"field": "name",
"optionItem": {
"label": "名称"
},
"optionConfig": {
"normalize": "text:40"
},
"optionJsx": {
"placeholder": "20个中文字符"
},
"span": 14
}
输入框如下:
aiHidden
aiHidden 直接作用于表单配置中的 hidden 节点,通常在字段配置中是不需单独配置的,属于最特殊的渲染器。
aiInputArray
-
此渲染器有别名
aiInputMulti,旧版使用aiInputMulti,以后所有开发中新版推荐使用aiInputArray(原组件名)。
多选项输入模式,此字段渲染使用了 web 库中的 <InputArray/> 组件,此组件可以帮助开发人员实现多行文本输入,且产生 [] 的表单值。配置如下:
{
"metadata": "dependValue,条件字段值,24,,aiInputMulti",
"optionJsx.styleInput": {
"width": "30%"
},
"optionJsx.depend.enabled": {
"dependType": [
"DATUM"
]
}
}
此处不深究 optionJsx.depend 的 依赖和影响 配置,这个组件中会包含一个操作按钮,您可以点击这个按钮动态追加输入文本行,每行文本会生成一个 Array 的项,最终生成形如:
[
"文本行一的文字",
"文本行二的文字"
]
aiInputNumber (A)
对应 AntD 中的 <InputNumber/> 组件,用于 数值 录入。配置如下:
[
"layoutLeft,输入框宽度,,100%,aiInputNumber,min=1,max=24",
"layoutRight,选择框宽度,,100%,aiInputNumber,min=1,max=24"
]
特殊配置
此组件会多一个配置 optionJsx.numeric,其数据结构如下:
{
"percent": "是否执行百分比计算",
"unit": "单位信息",
"unitPosition": "单位位置"
}
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
布尔值,若此值为 true 则数值会转换成带有 |
|
数值单位,用于表示当前数值携带的计量单位相关信息。 |
|
布尔值,若为 true,格式为 |
aiTextArea (A)
对应 AntD 中的 <Input.TextArea/> 组件,用于多行文本录入,默认场景下多行文本录入由于追加了 textarea 的 CSS 是不允许做尺寸更改的,这也是 Zero UI 中的限定,尺寸的更改有可能会更改布局导致问题。配置如下:
[
{
"metadata": "comment,备注,24,,aiTextArea,maxLength=1024",
"optionJsx.rows": 3
}
]
多行文本常用的两个属性如 rows, maxLength,不过这两个属性都不属于 特殊属性,实际是 AntD 原生属性。
:data-uri:
:table-caption!:
aiPassword (A)
对应 AntD 中的 <Input.Password/> 组件,主要用于密码录入,密码输入框有一个默认属性 visibilityToggle,此属性可用于切换密码的 显示和隐藏,若是只读模式自动隐藏。配置如下:
[
{
"metadata": "opassword,旧密码,14,,aiPassword",
"optionConfig.rules": [
"required,请输入旧密码",
{
"min": 8,
"message": "密码长度必须大于8个字符!"
}
]
}
]
密码框如下:
aiProtocol (A)
对应 AntD 中的 <Input/> 组件的一个变种,您可以直接录入带协议的URL地址,然后点击 解析 按钮,系统会根据 linker 的配置将协议拆分之后的数据填充到现有的表单中。
[
{
"metadata": "endpoint,FTP地址,16,99%,aiProtocol,placeholder=上传文件的完整路径,可直接使用ftp命令的路径地址。",
"optionJsx.config.linker": {
"hostname": "hostname",
"port": "port",
"username": "username",
"password": "password",
"path": "path"
}
}
]
上述配置存在于集成管理处理 RESTful、FTP 协议部分,您可以填写如下:
http://ox.engine.cn:8081/api/app
上述内容会被直接解析成:
{
"hostname": "ox.engine.cn",
"port": 8081,
"username": null,
"password": null,
"path": "/api/app"
}
由于此处处理的是 RESTful,所以 username 和 password 在此处无法解析,为空,若是 FTP 协议或其他协议,此处会解析得到对应的账号以及密码。
aiRadio (A)
对应 AntD 中的 <Radio.Group/> 组件,您可直接设置单选框信息,其配置如下:
[
{
"metadata": "method,HTTP方法,12,,aiRadio",
"optionJsx.config.items": [
"GET,GET方法",
"POST,POST查询"
]
}
]
选项说明
选项在 Zero UI 中主要使用在 aiRadio, aiSelect, aiCheckbox 三种最常见的 选择组件 中,这三种组件在 配置选项 时其用法一样:
-
静态配置,静态配置如示例中设置的,直接配置
optionJsx.config.items属性,此属性是一个[]结构,数字的每一个元素可直接解析成一个选项,如上述示例中会直接解析成:[ { "key": "GET", "value": "GET", "label": "GET方法" }, { "key": "POST", "value": "POST", "label": "POST查询" } ] -
动态配置,动态配置一般会使用字典配置
optionJsx.config.datum属性,此属性通常会书写成String的字符串格式:{ "metadata": "category,组类型,14,,aiRadio", "optionJsx.config.datum": "source=ajax.groups.type,value=code,label=name", "optionJsx.config.datumSort": { "field": "sort", "asc": true } }上述配置中,
datum配置了字典作选项的基本信息,而且还配置了额外的datumSort来处理选项的排序问题。一般情况选项会按照字典默认读取的顺序排列,若读取远程接口没有在服务端执行排序,那么就可以启用此处的datumSort属性按某个属性进行选项的排序。
单选框如下:
aiSelect (A)
对应 AntD 中的 <Select/> 组件,您可以直接设置下拉信息,配置如( 此处使用静态完整配置 ):
[
{
"metadata": "type,数据类型,19,,aiSelect,placeholder=必选",
"optionJsx.config.items": [
{
"key": "java.lang.String",
"label": "字符串"
},
{
"key": "java.lang.Integer",
"label": "整数"
},
{
"key": "java.lang.Long",
"label": "长整型"
},
{
"key": "java.lang.Boolean",
"label": "布尔值"
},
{
"key": "java.math.BigDecimal",
"label": "浮点数"
},
{
"key": "java.time.LocalTime",
"label": "时间格式"
},
{
"key": "java.time.LocalDate",
"label": "日期格式"
},
{
"key": "java.time.LocalDateTime",
"label": "日期/时间格式"
}
],
"optionConfig.rules": [
"required,请选择数据类型!"
]
}
]
aiCheckbox (A)
对应 AntD 中的 <CheckBox.Group/> 组件 或 <Switch/> 开关组件,一般情况下二选一的模式是最常用的。
两种模式之间的切换依赖 optionJsx.mode 属性,若此属性设置为 SWITCH 的值切换到 开关 模式,反之若使用 CHECKBOX(默认值不用填写)则切换到 勾选 模式。
启用/禁用
此组件最常用的一种模式是单个 CheckBox 的勾选:
[
{
"metadata": "active,启用,14,,aiCheckbox",
"optionConfig": {
"valuePropName": "checked"
}
}
]
上述模式几乎在每个表单中都存在,用于设置 启用/禁用 相关状态。
开关配置
除开上述的 勾选 之外,此组件还支持 开关 模式,配置如下:
[
{
"metadata": "isHidden,是否隐藏,8,,aiCheckbox",
"optionJsx": {
"mode": "SWITCH",
"checkedChildren": "隐藏按钮",
"unCheckedChildren": "显示按钮"
},
"optionConfig": {
"valuePropName": "checked"
}
}
]
多选配置
多选配置和 aiSelect / aiRadio 设置选项一样,此处就不重复讲解了,设置下边属性可开启多选:
-
optionJsx.config.items -
optionJsx.config.datum
aiDatePicker (A)
对应到 AntD 中的 <DatePicker/> 组件,可直接进行日期选择,配置如下:
[
{
"metadata": "signedAt,签订时间,,,aiDatePicker,placeholder=选择签订时间",
"optionJsx.format": "YYYY-MM-DD HH:mm",
"optionJsx.showTime": true,
"moment": true
}
]
日期选择器如下:
特殊配置
Zero UI中的日期选择器唯一的特殊配置是指定属性 moment=true,早期的 AntD 中的时间格式使用的是 moment.js 的库,这个库和新版的 Dayjs 库一样,对 undefined 是会报错的,而单纯从数据层面无法根据格式或其他值来判断当前属性是否 日期/时间,所以只能在表单这一级直接定义当前属性是一个 moment=true 的日期格式数据。再者日期格式除了此处的 <DatePicker/> 以外,还会有独立时间 <TimePicker/> 选择器,所以系统无法根据 moment.js 执行反算;其实真计算是可以的,但由于组件本身是逐渐开发出来的,<DatePicker/> 在 <TimePicker/> 之前,所以就懒得在原始组件上修改了,最终在组件上保留了 moment 这个属性来鉴别 时间/日期 类型的控件。
aiTimePicker (A)
对应到 AntD 中的 <TimePicker/> 组件,可以直接进行时间选择,配置如下:
[
"pTimeArrive,默认到店时间,,,aiTimePicker,format=HH:mm",
"pTimeLeave,默认离店时间,,,aiTimePicker,format=HH:mm",
"pOrderKeep,无效订单保留,,,,addonAfter=天"
]
时间选择器默认会被 Zero UI 直接追加 moment / true 的属性,所以后期升级之后此属性也可以逐渐被拿掉。时间选择器如下:
aiFileLogo
上传图标专用组件,此组件执行过封装,底层使用了 AntD 中的 <Upload/> 组件,但通过限定属性让此组件只拥有 图片上传/预览 的功能。配置如下:
[
{
"metadata": "logo,应用Logo,16,,aiFileLogo,listType=picture-card,text=上传",
"optionJsx.config.filekey": "key",
"optionJsx.config.limit": 10240,
"optionJsx.ajax.uri": "/api/file/upload/:identifier?category=:category",
"optionJsx.ajax.download": "/api/file/download/:key",
"optionJsx.ajax.params": {
"identifier": "FIX:x.application",
"category": "FIX:logo"
}
}
]
特殊属性
一般自定义组件都会包含部分定制过的 特殊属性,毕竟 Zero UI 中的所有自定义组件都需要支持纯描述的 配置模式。
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
此处的 |
|
上传文件的限制,单位为 |
|
上传专用路径信息,可包含类似 |
|
可根据上传文件生成对应文件的下载链接,下载链接是一个唯一的 |
|
参数配置,此参数主要针对 上传 行为执行定制,而且会影响上传的最终存储 集成目录。 |
图片上传组件如下:
aiFileBatch
批量上传组件,底层使用了 AntD 中的 <Upload/> 组件,配置如下:
[
{
"metadata": "files,文件上传,18,,aiFileBatch,text=上传",
"optionJsx.accept": "*/*",
"optionJsx.config.filekey": "key",
"optionJsx.config.limit": 10240,
"optionJsx.config.reduce": true,
"optionJsx.ajax.uri": "/api/file/upload/:identifier?directory=:directory",
"optionJsx.ajax.download": "/api/file/download/:key",
"optionJsx.ajax.params": {
"identifier": "FIX:x.notice",
"directory": "/系统文档/公告文档",
"formula": "/${name}"
}
}
]
特殊属性
(此组件特殊属性和前文 aiFileLogo 保持一致)。
|
此处要特别说明的是 |
批量上传组件如下:
aiFileUpload
批量上传组件,底层使用了 AntD 中的 <Upload/> 组件,配置如下:
[
{
"metadata": "record@file,文件下载,16,,aiFileUpload,text=上传",
"optionJsx.accept": "*/*",
"optionJsx.config.filekey": "key",
"optionJsx.config.limit": 10240,
"optionJsx.ajax.uri": "/api/file/upload/:category",
"optionJsx.ajax.download": "/api/file/download/:key",
"optionJsx.ajax.params": {
"category": "FIX:FILE.REQUEST"
},
"optionJsx.config": {
"linker": {
"key": "record@key",
"fileKey": "record@fileKey",
"name": "record@name",
"type": "record@type",
"size": "record@size",
"sizeUi": "record@sizeUi",
"extension": "record@extension"
}
},
"optionConfig.rules": [
"required,上传文件不可为空,请上传您要审批的文件!"
]
}
]
上述配置是 文件流程 中的特殊配置,前文中已经针对 特殊配置 有所说明了,此处先不讲 linker(放到后续专用组件中讲解)。
子字段 @
此处需要讲解一个特殊的 Zero UI 中的表单语法,通常模式下一个表单字段是类似 name 这种格式,但随着集成服务 zero-is 开启之后,Zero UI做了一次升级,本次升级中,让表单 <Form/> 的属性支持嵌套型,但由于 . 已经被 属性解析器 使用了,所以这种模式下使用 @ 做分隔符来区分主记录和子记录,如本示例中的 record@key,实际这些属性最终会执行转换。
{
"record@key": "key1",
"record@name": "name1",
"record@size": 96
}
上述格式最终会转换成:
{
"record": {
"key": "key1",
"name": "name1",
"size": 96
}
}
上述转换流程会在表单提交过程中自动转换,且和表单绑定时也会自动执行,您无需做任何操作就可以实现这种级别的数据转换行为。 :data-uri: :table-caption!:
aiGroupSwitcher
此组件为 双态组件,Zero UI中的自定义组件,配置如下:
[
{
"metadata": "openGroup,工作组,8,,aiGroupSwitcher,readOnly=true",
"optionJsx.config.datum": "source=ajax.groups,value=key,label=name",
"optionJsx.config.bind": "groupOpen"
}
]
此组件的配置中直接和字典绑定了,配置了 optionJsx.config.datum 的值,这个组件最终会有两个状态:
-
若数据只有一条:只读状态和唯一的数据产生绑定,呈现相关信息,此时是只读状态。
-
若数据有多条:直接使用下拉可选择合法的值,此时是可编辑状态。
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
值捆绑配置,此处设置为 |
aiCaptcha
验证码专用自定义组件,此组件用于呈现验证码并生成验证码。配置如下(登录页专用,全配置格式):
[
{
"field": "captcha",
"$render": "aiCaptcha",
"optionConfig": {
"rules": [
{
"required": true,
"message": "请输入验证码!"
}
]
},
"optionJsx": {
"placeholder": "验证码",
"prefix": {
"type": "code"
},
"config": {
"type": "image",
"ajax": {
"uri": "/captcha/image",
"method": "POST"
},
"error": {
"501": "对不起,您的服务端不支持验证码功能!"
}
}
},
"optionItem": {
"hasFeedback": true
}
}
]
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
当前验证码的基本类型,默认使用图 |
|
远程接口专用配置,若要支持验证码功能那么验证码本身必须从服务端生成并呈现在客户端,验证码在点击时会重新发送请求自动刷新,Zero Extension中默认路径使用 |
|
如果出现了错误则直接以异常的方式呈现在界面上,如:服务端不支持等。 |
验证码组件如下:
aiJsonEditor
标准的Json编辑器,内置使用可格式化高亮的Json,配置如下:
[
{
"metadata": "options,额外配置,24,,aiJsonEditor",
"optionJsx.height": 160
}
]
此组件除了高度以外其他内容不用设置,最终提交出来的数据为 {} 或 [] 的 JSON 格式,一般此编辑器是用来编辑配置文件专用的交互式控件。
aiAddressSelector
专用地址选择器,用来选择:国家/省会/城市/二级市 四个层级专用的选择器,由于此选择器目前在项目中没有整体使用,所以现阶段没有直接可参考的配置代码,暂不做说明,后续来补充。
aiCheckJson
JSON格式的多选组件,和 aiCheckbox 的不同点在于输出的数据格式有所区别:
-
aiCheckbox中的选中输出值为:[v1, v2]的格式。 -
aiCheckJson中的选中输出值格式为Object的格式。
使用配置如下:
[
{
"metadata": "metadata,基本配置,24,,aiCheckJson",
"optionJsx.config.items": [
"design,可设计",
"deletion,可删除"
]
}
]
上述选择结果中,最终会生成如下数据格式:
{
"design": true,
"deletion": false
}
aiListSelector
(高频组件)常用的列表选择器,选择关联数据专用。配置如下:
[
{
"metadata": "username,关联账号,8,,aiListSelector,placeholder=(请选择账号)",
"optionJsx.config": {
"ajax": {
"metadata": "POST,/api/user/search,1,10,sorter=updatedAt`DESC",
"params.criteria": {
"sigma": "PROP:app.sigma",
"": "OPERATOR:AND"
}
},
"linker": {
"key": "userId",
"username": "username",
"realname": "viceName",
"email": "viceEmail",
"mobile": "viceMobile"
},
"table": {
"columns": [
"username,用户账号",
"realname,用户名称",
"mobile,手机号",
"email,邮箱"
]
},
"validation": "请选择关联账号!",
"window": "关联账号,选择,关闭,false,800,false",
"search": {
"username,c": "账号",
"realname,c": "姓名"
}
},
"optionJsx.allowClear": true
}
]
这个组件用于从另外一张表筛选数据关联到当前属性中,属于相对比较复杂的 组件。
列表选择器如下:
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
Ajax远程通信专用配置,此处配置支持 属性解析器,且使用了查询引擎的基本语法,参考 |
|
Zero UI中专用的 |
|
弹出的对话框中的表格专用配置,此表格配置遵循列表配置规范,可以像 主列表 一样配置。 |
|
选择验证的提示文字,启用了此组件之后,在弹出的对话框中您需要选择某一行数据做选项,若不选择则无法点击。 |
|
弹出框的基本配置,此配置支持 属性解析器 中的弹出窗口解析。 |
|
搜索框配置,您可以在弹出框中设置搜索功能,具体搜索参考查询引擎专用语法,此处生成: |
linker配置
Zero UI中的 linker 配置也属于高频配置,通常位于:
{
"optionJsx.config.linker": {
"from1": "to1",
"from2": "to2",
"...": "...",
"fromN": "toN"
}
}
上述数据结构中,fromX 表示选中记录中的属性,而 toX 则表示当前表单中的属性,当您触发了选择操作之后,就可以将对应属性拷贝到表单上(右值绑定表单),上述结构参考下图:
从图上可以看出 linker 的核心值拷贝原理。
|
列表选择器基本属于 Zero UI 开发过程中的高频组件,基本可以让你完成 双表连接 的前端交互操作,只要后端的API是准备好的,那么这种双表连接不论是否支持外键都是一种前端交互的最优选择,而且弹出的对话框本身是支持:分页、查询、跳页 等列表功能的,可以当做是一个列表的简易版本。 |
前端所有的 Selector 级别的配置都是双字段配置模式,简单说表单中必须包含两个字段与之对应,假设目前有一个表单属性:category,那么这个属性通常配置 Selector 时会使用:
-
categoryName:虚拟属性,此属性在后端可以没有任何模型与之对应,只是单纯用于 组件呈现。 -
category:实际属性,此属性才是最终存储在模型中的值,此属性一般配置到hidden中。
这种做法的核心原因是早期的表单开发不成熟导致,由于本身使用过程没有出现过问题,所以就没有再重新定义组件来更改,其中常用的 Selector 包括:
-
ListSelector -
UserSelector -
TreeSelector -
AddressSelector(地址选择器在某些场景中直接使用级联下来完成)
aiTreeSelector
专用树型选择器,和列表选择器的配置比较类似,只是弹出框是 树 的数据结构。配置如下:
[
{
"metadata": "bankName,上级银行(父行),8,,aiTreeSelector,placeholder=(请选择)",
"optionJsx.config": {
"ajax": {
"uri": "/api/bank/by/sigma",
"magic": {
}
},
"linker": {
"name": "bankName",
"key": "bankId"
},
"selection": {
"multiple": false,
"checkStrictly": true
},
"tree": {
"title": "name",
"parent": "bankId"
},
"validation": "请选择父行!",
"window": "选择父银行,选择,关闭,false,400,false"
},
"optionJsx.allowClear": true,
"optionJsx.depend.enabled": {
"branch": true
}
}
]
树型选择器如下:
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
Ajax远程通信专用配置,此处配置支持 属性解析器,且使用了 |
|
Zero UI中专用的 |
|
属性选择器的专用配置,您可以设置属性选择器的选择模式,包括 多选、单选。 |
|
针对查询的数据源的树相关配置(如何构造一颗树提供选择)。 |
|
选择验证的提示文字,启用了此组件之后,在弹出的对话框中您需要选择某一行数据做选项,若不选择则无法点击。 |
|
弹出框的基本配置,此配置支持 属性解析器 中的弹出窗口解析。 |
aiMatrixSelector
矩阵选择器,更为复杂的选择器功能,参考配置如:
[
{
"metadata": "actions,关联操作,24,,aiMatrixSelector",
"optionConfig.rules": [
{
"validator": "required",
"message": "对不起,关联操作不可为空,请添加关联操作!"
}
],
"optionJsx.config": {
"ajax": {
"metadata": "POST,/api/action/search,1,10,sorter=updatedAt`DESC",
"params.criteria": {
"permissionId,n": true
}
},
"table": {
"columns": [
"name,操作名称",
"code,操作编码",
{
"metadata": "method,HTTP方法,MAPPING",
"$mapping": {
"GET": "GET,download,,#268941",
"PUT": "PUT,edit,,#0a7bed",
"POST": "POST,plus,,#f6af03",
"DELETE": "DELETE,delete,,#e22015"
}
},
{
"dataIndex": "uri",
"title": "请求路径"
}
]
},
"validation": "请选择关联操作!",
"window": "关联操作,选择,关闭,false,980,false",
"search": {
"name,c": "名称",
"code,c": "编码"
},
"selection": {
"multiple": true,
"multipleMode": {
"replace": false
}
},
"dynamic": {
"dataIndex": "key",
"title": "添加",
"config": {
"text": "移除",
"confirm": "该操作会从当前权限中移除选中操作,确认?"
}
}
}
}
]
矩阵选择器的基本配置和 ListSelector 近似,但多了部分复杂的操作,此部分选择的交互式操作在权限管理中有说明,到时候开发中心开发 权限管理 时再回头来补充本章节的详细教程。
aiDialogEditor
子记录编辑器,此组件主要用于编辑某个记录的自己录专用,如:订单 / 订单项 的编辑模式,且这个组件应该算是 Zero UI 中最复杂的组件,很多时候要配合容器配置来进行深度定制。参考配置如下:
[
{
"metadata": "permissions,,24,,aiDialogEditor",
"optionConfig.rules": [
{
"validator": "required",
"message": "对不起,权限集中包含的权限不可为空!"
}
],
"optionJsx.config": {
"form": {
"window": 0.16,
"columns": 2,
"ui": [
[
{
"metadata": "resourceType,资源分类,14,,aiSelect,placeholder=选择资源类型",
"optionJsx.config.datum": "source=resource.type,value=code,label=name",
"optionJsx.depend.impact": {
"reset": [
"identifier",
"modelKey"
]
},
"optionConfig.rules": [
"required,请选择资源分类!"
]
},
{
"metadata": "modelKey,关联模型,10",
"optionConfig.rules": [
"required,请选择该分类下的关联模型!"
]
}
],
[
"identifier,模型ID,18,,,readOnly=true"
],
[
{
"metadata": "sourcePermission,选择现有权限,24",
"optionJsx.config": {
"titles": [
"可选择的权限列表",
"引用权限详情"
],
"record": {
"title": "(未选择引用权限)",
"selected": "已选择",
"data": {
"name": "权限名称",
"code": "权限代码",
"identifier": "所属模型"
}
},
"table": {
"columns": [
{
"dataIndex": "name",
"title": "权限名称"
}
]
}
}
}
],
[
{
"metadata": "name,权限名称,14",
"optionConfig.rules": [
"required,请填写权限名称!"
]
},
{
"metadata": "code,权限编码,10,,,placeholder=推荐以 perm 开头的系统助记码",
"optionConfig.rules": [
"required,请填写权限编码!"
]
}
],
[
"comment,权限备注,18,,aiTextArea,rows=5"
],
[
{
"metadata": "$button",
"hidden": true,
"optionJsx.extension": [
"$opSavePerm,保存,SAVE_ROW,primary",
"$opReset,重置,RESET"
],
"span": 24
}
]
],
"hidden": [
"key"
]
},
"dialog": "权限设置,保存,关闭,false,1150,true,$opSavePerm",
"op": {
"add": "$opShowPerm"
},
"table": {
"limitation": 12,
"columns": [
{
"title": "操作",
"dataIndex": "key",
"fixed": "left",
"$render": "EXECUTOR",
"$option": [
{
"text": "编辑",
"executor": "fnEdit"
},
"divider",
{
"text": "移除",
"executor": "fnDelete",
"confirm": "该操作会从此权限集中移除权限信息,将权限转换成`自由权限`,确认移除?"
}
]
},
"name,权限名称",
"code,权限编码",
"identifier,模型标识"
]
}
}
}
]
这个组件实际是一个综合组件,它的 交互式 本体就是一个列表组件,所以会有类似 table 的配置出现,而点击 添加/编辑 时它的子组件是一个表单 <Form/>,所以此处又会包含 form 节点的配置,除去这两部分的配置之后,剩余的配置部分就很容易理解了。
子记录编辑器如下:
特殊配置
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
子组件表单配置(遵循表单配置格式)。 |
|
弹出窗口相关配置。 |
|
添加按钮或附加按钮专用配置(表格右上角)。 |
|
交互式组件表单配置(遵循列表配置格式)。 |
|
|
aiTableEditor
表格编辑器,和 DialogEditor 类似,不同点在于表格编辑器不会有弹出框,通常直接在表格中编辑相关数据。配置如下:
[
{
"metadata": "payment,付款方式,24,,aiTableEditor",
"optionJsx.config": {
"format": {
"type": "ARRAY",
"keyField": "name"
},
"table": {
"className": "ux_table_secondary",
"columns": [
· {
"metadata": "quantity,数量,ROW",
"$config": {
"field": "aiInputNumber",
"jsx": {
"min": 1
}
}
},
{
"metadata": "price,单价,CURRENCY"
},
{
"metadata": "amount,金额,TOTAL",
"$config": {
"currency": "¥",
"op": "M",
"field": [
"quantity",
"price"
]
}
}
]
}
}
}
]
当前组件中没有需要特殊说明的属性,基本遵循 table 的列表配置,但是此处需要讲一下 optionJsx.config.format 配置,这个配置为表格编辑器定义了数据的基本格式,如:
{
"type": "ARRAY",
"keyField": "name"
}
-
type定义了当前编辑器提交的数据格式,此处支持的数据格式如下:格式 含义 OBJECT标准的 Json Object 格式,对应 JavaScript 中的
{}。ARRAY标准的 Json Array 格式,对应 JavaScript 中的
[{},{}]。ARRAY_MAP直接将一个 Json Array 格式按某个字段转换成
{}的格式,每一个key = value中value是单条记录集:{}。ARRAY_PURE纯 Array 格式,对应 JavaScript 中类似
["",""]这种,和ARRAY不同点在于每个元素都是一个 纯值。ARRAY_GROUP直接将一个 Json Array 格式按某个字段转换成
{}的格式,每一个key = value中的value是一个 Array:[]。 -
keyField由于是多记录表格编辑器,用此属性用于指定按什么字段执行去重,此属性定义的是记录的 业务标识规则。
表格编辑器如下:
列渲染器中一直存在 EDITOR 和 ROW 两种不同的列处理流程,这是设计上的一种失误,正常来说表格编辑都应该是带 index(索引)的模式,但由于在 AntD 的干扰下,<Form/> 内的组件和自定义组件的 onChange 函数层面有很大的不同,新版已经逐步统一,但在早期 AntD 3.x 的版本中双向绑定的原因,使得表格内编辑出现了类似 onChange 函数签名不一致的情况,为了兼容这种情况,Zero Ui提供了 EDITOR 和 ROW 两种列渲染器,针对不同的场景执行兼容型处理。这里未来是否可以统一还有待商榷,但目前引起的大部分表格编辑的 BUG 都是由于此处引起的,所以特此备注。
aiTransfer
内部封装了 AntD 中的 <Transfer/> 组件,但实际是自定义组件,用于设置左右穿梭框交互式操作,配置如下:
[
{
"metadata": "roles,用户角色,24,,aiTransfer",
"optionJsx.config.datum": "source=ajax.roles,value=key,label=name",
"optionJsx.config.valueKey": "key",
"optionJsx.config.titles": [
"待选择",
"已选择"
]
}
]
左右穿梭框如下:
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
当某些记录选中之后,使用记录中哪个属性的值作为最终的选中值: |
|
当前穿梭框的左右侧的标题设置。 |
aiTag (A)
对应 AntD 中的 <Radio.Group/> 组件变种,您可直接设置单选框信息,这种为特殊单选框,其配置如下:
[
{
"metadata": "color,标签颜色,,,aiTag",
"optionJsx.config.items": [
"geekblue,极客蓝",
"magenta,粉红",
"red,红色",
"volcano,火山红",
"orange,橙色",
"gold,金色",
"lime,青柠绿",
"green,绿色",
"cyan,青色",
"blue,蓝色",
"purple,紫色"
]
}
]
选项说明
此处选项为特殊选项,是为 antd 量身打造的色彩选项,色彩只可以删除或维持,不可以追加,运行截图如下:
注意若使用的是英文模式,则需要在英文资源包中追加英文相关配置!目前版本只支持上述简单配置,后续可支持特定配置实现这种特殊效果。
aiTableTransfer
表格穿梭框,更为复杂的穿梭框组件,配置如下:
[
{
"metadata": "items,选择商品,24,,aiTableTransfer",
"optionJsx.config.datum": "source=hotel.commodity,key=key,label=code",
"optionJsx.config.tree": "text=:name(:code),parent=parentId",
"optionJsx.config.filter": [
"code",
"name",
"helpCode"
],
"optionJsx.config.search": {
"placeholder": "商品编码/名称/助记码"
},
"optionJsx.config.checkable": "leaf",
"optionJsx.config.initialize": {
"payTermId": "termId",
"quantity": "NUMBER:1"
},
"optionJsx.config.table": {
"columns": [
{
"dataIndex": "key",
"title": "操作",
"$config": {
"text": "删除",
"confirm": "确认从选中项中移除该项目?"
}
},
"name,商品名称",
{
"metadata": "payTermId,账单项,ROW",
"$config": {
"field": "aiTreeSelect",
"jsx": {
"style": {
"width": "160px"
},
"config": {
"datum": "source=term.all,key=key,label=name",
"tree": "text=label,parent=parentId",
"selection": "mode=LEAF,field=isLeaf"
}
}
}
},
"code,代码",
"unit,单位",
{
"metadata": "quantity,数量,ROW",
"$config": {
"field": "aiInputNumber",
"jsx": {
"min": 1
}
}
},
{
"metadata": "price,单价,CURRENCY"
},
{
"metadata": "amount,金额,TOTAL",
"$config": {
"currency": "¥",
"op": "M",
"field": [
"quantity",
"price"
]
}
},
{
"metadata": "helpCode,助记码"
}
]
}
}
]
表格穿梭框如下:
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
左侧构造树型结构的基础数据源,此处从字典数据中加载和读取。 |
|
左侧树的构造配置,符合 Zero UI 中的标准树型配置结构。 |
|
左侧过滤栏(可直接过滤树结构,主要是过滤子节点)。 |
|
左侧搜索框相关配置, |
|
左侧树的选择模式, |
|
从左侧 树记录 转换到右侧表格记录时的字段映射转换关系,每次初始化时的数据提取映射配置。 |
|
右侧列表配置,配置右侧的表格列等相关信息。 |
aiTreeSelect (A)
对应 AntD 中的 <TreeSelect/> 组件,树型下拉组件,一般数量不多的时候使用属性下拉比属性选择器合理。配置如:
[
{
"metadata": "termId,账单项目,,,aiTreeSelect",
"optionJsx.config.datum": "source=term.all,key=key,label=code",
"optionJsx.config.expr": ":name(:code)",
"optionJsx.config.tree": "text=label,parent=parentId",
"optionJsx.config.selection": "mode=LEAF,field=isLeaf",
"optionJsx.config.linker": {
"key": "termId",
"name": "termName"
},
"optionConfig.rules": [
"required,请选择合法的账单项!"
]
}
]
特殊属性
配置属性表:
| 属性路径 | 含义 |
|---|---|
|
当前树型下拉的数据源,从字典中提取。 |
|
设置属性下拉的显示文字,支持前端的表达式方式,这种方式可更改下拉项的文字显示内容。 |
|
树型下拉的树相关配置,符合 Zero UI中的树基础配置。 |
|
Zero UI中的树选择模式设置,此处只能选择叶节点。 |
aiUserGruop
用户组专用选择器,账号管理 中专用,新版选择器,为用户选择用户组信息的专用组件。配置如:
[
{
"metadata": "groups,用户组,24,,aiUserGroup"
}
]
用户组选择器如下:
aiUserLeader
经理选择器,专用用户经理选择,目前应用在 业务流程 中选择处理组相关信息,配置如下:
[
{
"metadata": "runDept,处理组,24,,aiUserLeader",
"optionJsx.config": {
"items": [
"a,A组",
"b,B组",
"c,C组",
"d,D组"
],
"title": {
"managerName": "组长",
"workNumber": "组长工号",
"mobile": "组长手机"
}
}
}
]
|
组处理流程中,用户可以选择此处指定的 它描述了这样一种场景,一个任务要分配到不同的组去完成,分配时根据实际情况先选择组以及组中的负责人,然后执行分配之后的任务流程。 |
aiUserSelector
用户选择器,内置封装了 ListSelector,和当前 Zero Extension 中的员工模块配合,实现用户信息的选择功能。配置如下:
[
{
"metadata": "acceptedName,当前处理人,8,,aiUserSelector,readOnly=true,placeholder=(谁将会审批该工单)",
"optionJsx.config": {
"linker": {
"key": "acceptedBy",
"realname": "acceptedName"
},
"user": "处理人"
},
"optionJsx.allowClear": true
}
]
从上述配置可以知道选择配置比 ListSelector 大大简化,用户选择器如下:
此组件和 ListSelector 组件唯一的区别就是弹出框的内容差异,所以推荐使用此组件做 员工/人员选择。
aiAction
前文已经带着开发人员了解了 Zero UI 中所有标准表单交互式组件,本章详细讲解提交按钮的配置,提交按钮在 Zero UI 中十分特殊,先看一段参考配置:
[
{
"metadata": "$button",
"hidden": true,
"optionJsx.extension": [
"$opSave,保存,SUBMIT,primary",
"$opDelete,删除,KEY",
"$opReset,重置,RESET"
],
"span": 24
}
]
在上述配置中,您可以看到几个比较特殊的属性:
-
metadata / field`属性:由于历史原因,此处的值必须是一个固定值 `$button,只有这个值可以被 Zero UI 捕捉到并注入提交按钮的行为。 -
hidden属性:在 属性解析器 章节您已经了解了 Zero UI 中的窗口连接模式:-
若此按钮不作为 连接点 按钮,而是直接作为可呈现的提交按钮对待,那么
hidden = false或不设置。 -
若此按钮作为 连接点 按钮对待,那么通常会设置
hidden = true将按钮隐藏,若您想要查看防重复提交过程,可以考虑此处hidden = false做调试。
-
-
span属性:如果按钮隐藏,此处设置什么值都无碍。
参考如下片段体会两种配置的区别(个人密码修改页)
[
{
"metadata": "$button,,14",
"optionJsx.extension": [
"$opPassword,更改密码,SUBMIT,primary",
"$opReset,重置,RESET"
]
}
]
由于按钮部分有可能存在多个按钮,所以第二占位符 optionItem.label 配置没有任何实际作用。
按钮配置
提交按钮在表单的骨架代码中一般如下:
<ExForm {...form} $height={"300px"} $op={Op.actions}/>
操作部分代码如:
import Ex from 'ex';
import Ux from "ux";
const $opPassword = (reference) => (params) => {
const user = Ux.isLogged();
const opassword=Ux.encryptMD5( params['opassword']);
if(opassword !== user.password){
return Ux.ajaxDialog(reference, {
key: "passwordError", /* 专用窗口对应的key */
});
}
const request = Ux.valueRequest(params);
request.password = params['npassword'];
return Ex.I.password(request)/* 更新密码回调处理 */
.then(data => Ux.ajaxDialog(reference, {
data, /* 响应数据 */
key: "password", /* 专用窗口对应的key */
}))
/* closed 参数这里不显示 */
.then(() => Ex.Op.$opLogout(reference));
};
export default {
actions: {
$opPassword
}
}
注意此处的配置行:
"$opPassword,更改密码,SUBMIT,primary"
这些内容对应的按钮配置如下:
| 索引 | 属性名 | 含义 |
|---|---|---|
0 |
|
如果作为 连接点,此处的 |
1 |
|
按钮中的文字,此文字会作为 |
2 |
|
事件名称,事件名称在按钮中属于重点配置
|
3 |
|
按钮类型,对应 |
4 |
|
按钮的 CSS 风格设置(可自定义风格,如 |
5 |
|
按钮上的图标,可支持 图标表达式。 |
6 |
|
原子解析属性 部分,您可以直接设置扩展属性。 |
带回调配置
表单的回调配置在早期的版本中都是位于 UI.json 中的根节点 _modal 中,而新版本中的窗口函数可以直接配置在 _form 内部实现内部的 闭合 回调。参考流程配置表单如下:
{
"_form": {
"modal": {
"success": {
"open": "您好,您的流程申请已成功提交,申请单号 :serial,请等待审批。",
"draft": "您好,您的流程申请已成功保存为草稿!单号为 :serial。"
}
},
"ui": [
[
{
"metadata": "$button",
"optionJsx.grouped": true,
"optionItem.label": "流程操作",
"optionJsx.extension": [
"$opStart,提交,SUBMIT,primary,,upload,closable=true,callback=open",
"$opDraft,暂存,SUBMIT,,uc_pink,,closable=true,callback=draft",
"$opReset,重置,RESET",
"$opBack,返回,BACK"
],
"span": 24
}
]
]
}
}
上述按钮配置中,您可以在 $KV$ 部分看到类似 closable=true,callback=open 的 原子解析配置 扩展,这种扩展会自动在回调完成之后执行自动化行为(零代码模式)。
-
closable-
如果这个值为
true,则提交之后会调用rxClose函数触发关闭行为,这种关闭包括:关闭弹窗、关闭页签、关闭抽屉窗 等。 -
如果这个值为
false,不做任何关闭操作,仅执行 表单重置。
-
-
上述示例中回调最终配置如下,按钮在提交之后会自动触发回调并完成 表单操作 闭环:
按钮ID 事件 回调键 配置路径 $opStartSUBMIT
open
modal/success/open$opDraftSUBMIT
draft
modal/success/draft
|
还有一种格式是最新版才追加的,为了避免手工设置
这种格式是 最新版 的 Zero Ui 支持的格式,主要目的是通过配置完成所有的表单级操作,但是此处的
这样配置之后,在
|
关于 event
按钮事件主要分为两部分:服务端(配置型)和 客户端(开发型)。
| 事件值 | 含义 |
|---|---|
|
过滤表单专用提交事件,提交的数据一般作为查询条件,使用在 高级搜索 中。 |
|
添加表单专用事件。 |
|
编辑表单保存时专用事件。 |
|
编辑表单删除时专用事件。 |
| 事件值 | 含义 |
|---|---|
|
标准的表单提交,一般在事件函数中开发 Ajax 远程接口请求。 |
|
(旧模式)触发 |
|
窗口表单提交,在弹出窗的 表单 中触发提交,执行完成之后关闭弹窗。 |
|
此事件一般用于子表单提交,类似 |
|
「不需函数」返回专用,触发 |
|
「不需函数」重置表单专用,提交完成之后重置表单。 |
|
只带记录 |
aiTitle
标题栏的定义方式和其他交互式控件有所区别,所以此处并没有类似 aiXxx 的函数对其进行渲染,此处介绍一下标题的渲染配置。
模块化标题
参考如下配置:
[
"subject=HOTEL-ORDER"
]
模块化配置结果如下:
这种配置位于 模块化参数 过程中,属于特殊标题栏配置,React 组件会从上层 props 中提取变量 $subject 变量中的配置信息,并生成截图中对应的标题栏,此标题栏会对应到后端 B_BAG / B_BLOCK 的结构中,所有配置数据都和表结构中存储的配置数据相关。
提醒文字
参考如下配置:
[
{
"title": "房态说明",
"config": {
"description": [
"停用房为最高优先级,一旦停用其他状态不可随意变更。",
"只有`可用房`会参与到主流程中,其他类型的房间在主流程中均不可用。",
"清洁状态可独立更新,辅助房务中心做房态调整。",
"`预离`和`预抵`房为特殊房态,且系统自动计算,不可维护,只可查看。"
]
}
}
]
这种配置的效果如下:
此配置对应的是 AntD 中的 <Alert/> 组件,所有属性都遵循它对应的信息,包括 message, description, type 等,您可以按自己的需要配置。
:data-uri:
:table-caption!:
aiMagic
数据呈现器,此组件专用于 非交互型 数据呈现,配置如:
[
{
"metadata": "method,HTTP方法,4,,aiMagic",
"optionJsx.config.items": [
"GET,GET:calendar,16:#228B22",
"PUT,PUT:calendar,16:#228B22",
"POST,POST:calendar,16:#228B22",
"DELETE,DELETE:thunderbolt,16:#D02090"
]
}
]
上述配置会捕捉对应数值,并生成 选项 呈现。
选项配置
选项配置一般位于 optionJsx.config.items 中,你可以设置两种配置:
-
原始配置,不带图标的基础配置:
"GET,GET方法" -
扩展配置,带图标的基础配置:
# 由于历史原因,此处的选项配置格式不要写错 "GET,GET方法:calendar,16:#228B22"
上述配置中几个值含义如:
| 值 | 含义 |
|---|---|
|
选项的值,对应 |
|
选项的显示文本,对应 |
|
图标类型,对应 |
|
图标的尺寸,对应 |
|
图标的颜色,对应 |
呈现器种类
-
列表呈现器,如果
value值是Array类型则自动触发列表呈现器。配置项 含义 optionJsx.config.vertical显示成水平列表还是垂直列表。
列表中的项支持递归,即内置的
<li></li>的呈现部分依旧可以是嵌套类型的aiMagic视图。 -
时间呈现器,如果
value的值是时间格式Ux.isMoment检查返回 true,则做时间格式呈现。配置项 含义 optionJsx.config.format时间格式化专用的模式字符串,如
YYYY-MM-DD。{ "metadata": "updatedAt,最后更新,,,aiMagic", "optionJsx.config.format": "YYYY年MM月DD日 HH:mm", "moment": true } -
选项呈现器,若配置中包含了
items的配置,则执行选项呈现器。配置项 含义 optionJsx.config.items当前环境可支持的选项数据,参考最早的示例。
optionJsx.config.datum如果选项使用的不是 静态数据 而是动态字典,则可支持直接从动态字典中提取数据。
-
记录呈现器,若配置中包含了
record配置,则执行记录呈现。记录解析之后会包含多种呈现模式,通常是采用 JSON 的方式直接呈现记录信息,若记录中带有解析的前缀
prefix,则可以考虑设置前缀而实现记录的 标题 部分。{ "metadata": "infoReadable,详细内容,19,,aiMagic", "optionJsx.config.record": true } -
用户呈现器,若配置中包含了
user配置,内置呈现和列渲染USER一致,所以其配置格式也是一致的。{ "metadata": "updatedBy,更新人,,,aiMagic", "optionJsx.config.user": { "uri": "/api/user/:key", "field": "realname" }, "optionJsx.$empty": "(系统)" } -
下载文件呈现器,若配置中包含了
download配置则采用下载链接呈现器。{ "metadata": "fileUrl,链接地址,24,,aiMagic", "optionJsx.config.download": { "text": "下载文件", "filename": "name" }, "optionJsx.config.preview": { "type": "type", "empty": "(该版本暂不提供预览功能)" } } -
表格呈现器,若配置中包含了
table配置,内置使用表格呈现器(列表配置)。 -
带单位文本
{ "metadata": "amount,退款金额,,,aiMagic", "optionJsx.config.currency": "¥" }
|
除了上图 呈现器 以外,其实呈现器还拥有其他特殊的配置,开发人员可直接参考源代码去了解,文档中的呈现器只是枚举了常用的。 |
aiSearchInput
Qr类型的组件只有两个自定义的比较特殊的组件,其他组件的用法可直接参考现有的 查询表单 来完善,如 Qr 在输入表单上的更改类似:
-
字段名一般会使用
`符号做分割(符号之后是查询操作符),配置如:"name`c,名称,24" -
如果是下拉类型的则多数都支持多选模式,包括
aiRadio / aiCheckbox / aiSelect的选项都是支持多选模式的,最终使用IN操作符。
此交互式组件为搜索专用的组件,一般在搜索表单中使用。配置如:
{
"metadata":"contactName,联系人姓名,12,,aiSearchInput",
"optionJsx.layout": {
"left": 14,
"right": 10
}
}
该查询组件如下:
aiSearchRangeDate
查询范围组件,配置如:
{
"metadata":"infoAt,日志记录时间,24,,aiSearchRangeDate",
"optionJsx.config":{
"mode":"FULL",
"format":"YYYY-MM-DD HH:mm",
"placeholder":["开始时间","结束时间"]
}
}
查询范围组件一般用于 时间格式 的查询过程中,此处就不截图了。
模式
| 值 | 含义 |
|---|---|
|
日期时间全格式 |
|
日期范围查询 |
|
月份范围查询 |
|
时间范围查询 |
验证规则
验证规则主要针对 optionConfig.rules 的配置部分的配置生效,您可以直接配置各种有用的验证器。参考配置:
{
"optionConfig.rules": [
"required,请输入仓库名称,名称不可为空!"
]
}
上述配置是最常用的配置,此处的规则中也可以直接使用 AntD 的默认验证器配置,由于默认验证器配置在官方文档中存在,所以就不在这里重复,本章主要讲解部分常用的 自定义验证器。
下边验证器都是自定义扩展验证器,所以标题中的值等价于 validator=<title>。
existing
存在性验证专用配置(高频验证器)。参考配置:
{
"validator": "existing",
"message": "对不起,支行名称重复!",
"config": {
"uri": "/api/bank/existing",
"method": "POST",
"params": {
"sigma": "PROP:app.sigma"
}
}
}
|
假设有表结构
此处配置可追加一个特殊配置
上述表达式中
上述属性
来执行编辑过程中存在性检查的当前记录排除,默认情况若主键本身是 |
uri
远程延迟验证,更广义的 Ajax 验证,可实现各种 不可思议 的验证方式,开发人员阅读源代码自行理解。
required
必填验证,此验证器和最早示例中的默认 required 有所区别,此验证器属于增强型,可检查 Array,Object 等复杂数据结构。
{
"validator": "required",
"message": "对不起,订单项不可为空,请添加订单项!"
}
max
最大值验证器(增强型)。
range
范围验证器。参考配置:
{
"validator": "range",
"config": {
"min": 0,
"max": 8
},
"message": "超预订数量只能在合理的 0 ~ 8 的范围!"
}
after
在目标时间之后
{
"validator": "after",
"message": "离店时间必须晚于到店时间!",
"config": {
"to": "arriveTime"
}
}
before
在目标时间之前
lessOr
增强型小于等于某值
great
增强型大于某值
greatOr
增强型大于等于某值
same / equal
相同值验证
{
"validator": "same",
"message": "两次输入密码不一致!",
"config": {
"to": "npassword"
},
"condition": [
"to.length >= 8"
]
}
diff
不同值验证
列表配置
列表开发
一般在一个完整的系统开发中,最高频的两种中后台管理页面就是:表单页和列表页,前文已讲解了表单页中的基本配置和组件用法,本章节开始带开发人员看看 Zero Extension 中提供的列表组件。
-
ExListFast:快速列表 -
ExListComplex:标准列表
可以说 ExListComplex 组件几乎是为后端的 zero-crud 量身打造的全功能模块,此列表支持 15 个标准接口,Zero Extension 中的支持的接口并非传统的 增、删、查、改 四个维度,追加了实战过程中常用的扩展维度(包括视图、高级搜索),从实践经验可以知道这种 复杂列表 在企业应用中才可支撑大量产品化、快速交付项目的基本需求,特别针对中后台管理页达到不错的管理效果。
本篇先不结合截图讲解列表页选项(此部分直接在 实战模块 中加以详细说明),先简单讲解一下 Zero Extension 中列表的基础知识,截图由零点科技有限公司(使用Zero的友人)提供。
功能表
Zero Extension 中列表的功能支持如下:
-
访问
/api/xxx/search查询分析引擎接口,实现列表页的基本呈现,包括:分页、排序、列过滤、跳页、查询。 -
ExListComplex 组件的页面流如下:
-
|
待完善的部分:
|
工作区域
截图中区域说明(区域标识以截图中蓝色文字为主):
| 区域标识 | 含义 |
|---|---|
|
添加操作区域,默认只带有 添加 按钮可直接打开 |
|
批量更新、批量删除区域,此处可扩展更多带有 选择模式 的批量行为,可直接扩展 |
|
搜索统一区域:设置查询条件、高级搜索表单、清空查询条件 等。 |
|
右上附加区域,导入、导出、列筛选、试图管理 等。 |
|
列表头部区域,列过滤、排序 等。 |
|
分页器,支持 分页、页尺寸设置、跳页 等常用分页功能。 |
配置概览
本文主要解析传入 ExListComplex 中的 config 属性的核心数据结构,让开发人员可以根据自己实际需要对列表进行扩展和定制。
UI.json 的基本结构如下:
{
"_page": {
},
"_assist": {
},
"_grid": {
"query": {},
"options": {},
"component": {},
"table": {}
}
}
上述结构是开发 列表页 的专用配置结构,配置项内容如下:
| 根节点 | 子节点 | 含义 |
|---|---|---|
|
此节点一般用于绑定 |
|
|
辅助数据开发,等价于表单内页的 |
|
|
|
当前列表组件默认查询条件,第一次查询依赖此 查询条件 读取远程列表数据。 |
|
选项数据,您可以更改此配置对 列表组件 进行各种设置。 |
|
|
常用扩展组件:批量编辑表单、导入表单、导出表单、视图管理、列筛选表单 等几个组件的相关配置都可以直接在此处设置。 |
|
|
表格组件,主要包含了 列渲染器,此处有一点需说明:
|
标准开发
标准方法开发中,你可以在页面这一级直接读取完整结构的列表配置,并将配置以 config 的属性传入 ExListComplex 组件中。参考如下代码:
import React from 'react';
import Ux from 'ux';
import FormAdd from './form/UI.Add';
import FormEdit from './form/UI.Edit';
import FormFilter from './form/UI.Filter';
import Ex from "ex";
import {ExListComplex} from "ei";
import Op from "./form/Op";
import {PageCard} from "web";
@Ux.zero(Ux.rxEtat(require("./Cab"))
.cab("UI")
.to()
)
class Component extends React.PureComponent {
state = {
$ready: false
};
componentDidMount() {
Ex.yiStandard(this).then(Ux.pipe(this));
}
render() {
return Ex.yoRender(this, () => {
const config = Ux.fromHoc(this, "grid");
/* 专用组件信息 */
const form = {
FormAdd, // 添加表单
FormEdit, // 更新表单
FormFilter // 搜索表单
};
return (
<PageCard reference={this}>
<ExListComplex {...Ex.yoAmbient(this)}
rxPostDelete={Op.rxPostDelete(this)}
rxAssist={Op.rxAssist(this)}
config={config} $form={form}/>
</PageCard>
)
}, Ex.parserOfColor("PxRBACGroup").page());
}
}
export default Component
上述代码是 Zero Extension 中用户组的管理入口页,如果使用这种方式开发列表入口页,注意如下几点:
-
外层组件可以直接使用
<div/>标签组件,你也可以按照示例中直接使用<PageCard/>组件(带有头、标题、按钮和右上 Extra部分的基础页面容器)。 -
componentDidMount中的Ex.yiStandard方法调用是 可选的,它取决于您的列表页中是否带有初始化数据部分_assist辅助数据,这些辅助数据可直接作用于 列表、表单 作为辅助字典数据来处理。 -
绑定资源文件之后,配置部分从
UI.json中的_grid中提取全列表配置。 -
此处依赖三个表单文件,且表单键值是固定的:
表单键 含义 FormAdd添加表单,
mode=ADD的表单组件。FormEdit更新表单,
mode=EDIT的表单组件。FormFilter高级搜索表单,直接提供高级搜索专用表单定制功能,您可定制不同的查询条件。
FormBatch(保留)后期拓展批量编辑中的自定义部分设置批量编辑专用表单。
-
示例代码中的
rxPostDelete / rxAssist不属于标准部分的代码,它属于定制部分,所以标准部分代码只需要实现如下功能即可:属性 含义 Ex.yoAmbient(this)Zero 扩展框架中的核心继承方法,可以帮助您针对上下文属性实现向下继承的功能,其中包括:
-
常用的辅助数据(
$a_)和字典数据($t_)。 -
常用的上层函数,函数前缀(
rx / fn / ix)。 -
全局数据:应用
$app、登录账号$user、路由$router等。
config读取到的
ExListComplex的完整配置数据,从UI.json的_grid节点提取。form传入
ExListComplex表单完整数据。 -
|
这种开发模式比 快速开发 模式多开发完整的 表单 页(三个表单页),不仅如此表单页所有行为函数都需开发人员提供( |
快速开发
快速开发依赖新库 ui 中提供的智能化开发模块。
Ui.smartList
smartList 的骨架代码如下:
import Ui from "ui";
import Ex from 'ex';
import Ux from 'ux';
export default Ui.smartList({
ns: require("./Cab.json"),
name: "Integration.SMS",
logger: "toolkit",
Options: {
rm: [
"form.filter", // 关闭高级搜索表单
"op.extra.export", // 按钮:导出
"op.extra.import", // 按钮:导入
"op.batch.delete", // 按钮:批量删除
"op.batch.edit", // 按钮:批量编辑
]
},
Form: {
name: "FormSms",
yoOp: {
A: "/api/i-integration",
S: "/api/i-integration/:key",
D: "/api/i-integration/:key"
}
},
componentInit: (reference) => {
Ex.yiAssist(reference, {})
.then(Ux.ready).then(Ux.pipe(reference))
}
})
快速开发模式主要调用 Ui.smartList 的API完成页面的综合性定制,此处针对 Ui.smartList 做个简易的说明,这个函数只有一个参数:
const smartList = (configuration = {}) => {
// ...
}
configuration 的配置项数据结构如下:
| 配置项 | 含义 |
|---|---|
|
关联名空间连接文件,此处必须调用 |
|
这个是页面名称,您可以随意设置页面名称,在开发过程中此名称会出现在浏览器的开发工具 |
|
可使用的日志器,日志器必须是合法日志器,参考 日志器 章节。 |
|
(驼峰命名),若不指定此选项,那么当前页面会直接绑定到 名空间 下 |
|
(驼峰命名),您可以设置 |
|
(驼峰命名),此处的
|
| 配置项 | 含义 |
|---|---|
|
对应 React 中的 |
|
对应 React 中的 |
|
对应 React 中的 |
| 配置项 | 含义 |
|---|---|
|
扩展属性 |
|
扩展属性 |
|
扩展属性 |
|
扩展属性 |
|
扩展属性 |
|
列表之下的 附加渲染器,可渲染额外区域的相关组件。 |
Ui.smartForm
smartForm 实际是快速绑定表单专用资源文件实现表单级的快速开发模式,这种场景下不需要您提供额外的表单代码文件,外层若调用 smartList,那么此处的 Form 配置中的每一种表单配置都会触发一次 smartForm 实现标准模式下三种表单的快速配置流程。
此函数签名如:
const smartForm = (configurationForm = {}, mode) => {
// ....
}
ns |
关联名空间连接文件,此处必须调用 require 方法连接名空间。 |
|---|---|
|
这个是表单名称,您可以随意设置表单名称,在开发过程中此名称会出现在浏览器的开发工具 |
|
(驼峰命名),默认会使用标准化代码针对 |
| 配置项 | 含义 |
|---|---|
|
对应 React 中的 |
|
对应 React 中的 |
|
对应 React 中的 |
|
表单特殊的生命周期执行,在 |
| 配置项 | 含义 |
|---|---|
|
扩展属性 |
|
扩展属性 |
|
扩展属性 |
|
扩展属性 |
|
上述提供的所有
|
快速配置
若您使用了 Ui.smartXxx 的方式做 列表 和 表单 的快速开发,那么配置文件也会大大简化(达到了快速开发的目的)。参考配置如:
{
"_assist": {
"zero.integration": {
"uri": "/api/type/tabulars/:type",
"magic": {
"type": "FIX:zero.integration"
}
}
},
"_grid": {
"module": {
"NAME": "邮件配置",
"MODULE": "i-integration",
"IDENTIFIER": "i.integration"
},
"query": {
"criteria": {
"sigma": "PROP:app.sigma",
"type": "email",
"": "OPERATOR:AND"
}
},
"options": {
"tabs.title": "Email服务器配置",
"tabs.container": true,
"search.advanced": false
}
}
}
上述配置文件需说明:
-
_assist部分依旧,用于提取辅助数据,不仅如此,若要加载辅助数据您还需在componentInit中手工书写代码(类似componentDidMount函数)。 -
module参数,此参数用于模块鉴别,参数含义如下:参数名 含义 NAME呈现当前模块的显示主体模型文字。
MODULE对应
crud模型中的name,构造标准化模块时:actor部分专用。IDENTIFIER当前管理模块的模型标识符。
-
query.criteria参数,直接书写当前页面的Qr查询参数。 -
options参数,若您不想使用默认值,则可以直接在此处更改options配置参数对列表进行修订。 :data-uri: :table-caption!:
Option选项配置
选项:搜索类
搜索类选项设置都采用 search 作为前缀,定义了列表的如下功能:
-
基础搜索
-
高级搜索
-
视图管理(查询条件部分)
搜索类参考配置如下:
{
"search.cond": [
"name,c",
"code,c"
],
"search.enabled": true,
"search.confirm.clear": "该操作会清空所有的查询条件,确认清空?",
"search.op.redo": "清除条件",
"search.op.advanced": "高级搜索",
"search.op.view": "查询条件",
"search.placeholder": "名称/编码",
"search.advanced": true,
"search.advanced.width": "40%",
"search.advanced.title": "搜索用户组",
"search.advanced.notice": {
"message": "注意!",
"description": [
"高级搜索条件优先级会大于普通搜索,一旦触发,普通搜索条件会被重置。",
"高级搜索表单中的搜索条件会被保存,再次打开时会重置到上次的搜索状态。"
]
},
"search.criteria.window": "当前查询条件,保存,关闭,false,900,true,btnCriteria",
"search.criteria.view": {
"selected": "当前视图:",
"confirm": "您正在更改当前视图的查询条件,一旦更改后查询数据会有变化,确认?"
}
}
search.cond
列表主页搜索框中的查询命中条件,此处查询命中条件会构造成 OR 的方式执行查询,如示例中会生成SQL语句:
-- NAME / name, CODE / code
WHERE NAME LIKE '%xx%' OR CODE LIKE '%xx%'
search.enabled
基础搜索框的开关,若此处 search.enabled = false 则自动隐藏列表头部的搜索框。
search.op.redo
是否呈现搜索框右侧的 清除条件 的按钮,若存在该选项则显示,且值为鼠标移上去过后的浮游文字。
search.op.advanced
设置搜索框右侧的 高级搜索 的按钮文字,高级搜索会使用另外一个配置来指定 开/关,所以高级搜索功能打开时若没有设置当前选项只是不显示浮游文字,但高级搜索功能依旧可用。
search.op.view
是否呈现搜索框右侧的 查询条件 的按钮,若存在此选项则显示,其值为鼠标移到按钮上的浮游文字。
search.advanced
和 search.enabled 类似,此按钮是高级搜索的开关,您可以设置此选项开启或关闭高级搜索。
search.advanced.width
高级搜索是在右边以抽屉的方式弹出界面,抽屉窗口中是一个 查询条件设置表单 ( FormFilter),此属性设置窗口位于页面中的宽度,若您的查询条件比较多可以考虑将此值设置得更大。
search.advanced.title
抽屉窗口顶部的标题文字,您可以自定义呈现的文字信息。
search.criteria.notice
查询条件 弹框顶部可设置提示消息,此提示消息可以显示在弹框顶部,和高级搜索提示文字格式一致。
search.criteria.window
若开启了 查询条件 设置的功能,此属性指定了查询条件弹出窗口的相关配置,内置使用了 组件解析器 解析该窗口。
search.grid
列表模板选择,您可以按照您所喜好设置对应的 grid 信息,系统有默认值存在。
选项:页签部分
页签配置主要是针对 <Tab/> 类组件,此处设置相对比较简单,支持两种模式:
-
若外层页带了
<PageCard/>做主容器,此种场景下页签可使用 标准模式 配置。 -
若外层页没有使用任何容器组件,页面可以作为独立容器来使用,这种场景下您依旧可以设置顶部的标题。
页签部分选项参考配置:
{
"tabs.title": "FTP配置",
"tabs.container": true,
"tabs.list": "FTP配置列表",
"tabs.add": "添加FTP配置",
"tabs.edit": "编辑FTP配置"
}
tabs.container
此选项用于切换当前页签的模式:标准模式 / 独立容器模式,若值为 true,那么页签容器可以自带标题信息,而忽略外层容器对象。
tabs.title
当页签使用 独立容器 模式时,您可以通过此选项指定页签的 标题 文字。
tabs.list
列表页页签头文字。
tabs.add
列表打开添加页时( mode=ADD ),页签头文字。
tabs.edit
列表打开编辑页时( mode=EDIT ),页签头文字。
tabs.type
对应 <Tab/> 组件的类型,直接绑定到 AntD 的原生属性中。
tabs.count
当前页面可以打开的最大数量,设置数量之后,您不可以随意打开多余的页签。
tabs.disabled
是否开启 单列表 功能,当前 ExListComplex 列表页是开启了 单列表 功能的,效果如下:
当你打开了 添加页/编辑页 时,第一个列表页的 页签 目前是被禁用的,只有关闭打开页签之后才可以回到列表中操作。
|
此处这种 集中 处理的设计有助于使用者将精力集中在当前界面应该考虑的部分,而不至于分心去不同页签上操作不同单据,很多大企业的此部分没有做这样的改动,用户可以无限打开页签,事实证明很多错误信息的填写都是出现在页签和页签进行切换过程中,企业数字化流程中,Zero 推荐用户的 单一职责 模式处理业务,若您现在正在处理单个工单,那么您就集中精力处理此工单,而不要分心做其他事。 |
tabs.extra.add
添加页右上角 Extra 的内容配置,可注入行为对容器右上角进行特殊的定制。
tabs.extra.edit
编辑页右上角 Extra 的内容配置,可注入行为对容器右上角进行特殊的定制。
选项:视图/模块
模块和视图选择和安全视图在列表层处理有关,Zero Framework中的视图处理如下:
| 视图参数 | 含义 |
|---|---|
|
当前接口位于的视图信息。 |
|
当前接口位于的位置信息,位置信息位于视图信息的高阶,您可以先指定位置,再指定视图。 |
而此处的模块和视图的参数命名规则本身未统一,但位于不同的分类之下,由于这些参数定义的内容一致,所以放到一起来讲解。
{
"identifier": "datum.room-rent",
"ajax.module": false,
"ajax.position": [
"ROUTE:type"
]
}
identifier
当前列表绑定的后端模型统一标识符,此属性很重要,动态建模过程中甚至会影响到模型的形态问题,按 Zero Extension 部分的整体规划,模型后期可通过 identifier 从服务端的模型接口拉取当前模型相关的所有定义,而每个列表都会绑定一个 主模型。
ajax.module
若系统做了多表连接( JOIN 模式),使用 父主表 模式时,管理模型的子表依赖核心参数 module 来绑定子模型的 identifier 标识符,此选项用于开启当前列表是否支持 module 参数,若不打开那么所有管理模式只会针对父模型进行管理,不会干涉到子模型的管理流程。
ajax.position
由于 ExListComplex 组件中已经存在视图管理,即 视图 相关的 view 参数本身就已经和个人设置执行了绑定,此参数用于鉴别 页面位置,示例中的定义可以看到当前页面配置的位置是根据路由中的 type 参数指定。当前选项是一个 Array 类型,所以您可以设置多个值来鉴别位置信息。最简单的场景是:
-
待审批的工单,position 可以根据工单状态
status来决定。 -
已审批的工单,position 可以根据工单状态
status来决定。
这种场景下您就可以设置 ajax.position 来对位置参数进行设置。
选项:动态
列表中的动态设置主要负责对 列 和 操作 进行控制,参考配置如下:
{
"dynamic.op": false,
"dynamic.column": false,
"dynamic.switch": false
}
dynamic.op
此属性用于控制所有 操作类 的选项:
-
false:操作类 的所有选项直接以options中配置的为准,严格控制了当前列表所有允许的操作配置。 -
true:操作类 的所有选项直接通过接口/api/ui/ops读取,形成动态配置且可以直接在接口层执行 权限控制。
dynamic.column
此属性用于控制 table 中的列配置选项:
-
false:列表的列以table.columns中定义的列为准,纯前端资源文件定义列表列。 -
true:列表的列通过接口/api/columns/<module>/full读取,此处module为当前列表绑定的模型在zero-crud中形成的标准化接口。
dynamic.switch
此属性用于控制页面流程相关操作,mode=ADD 和 mode=EDIT 是否执行智能切换。
-
false:不执行智能切换,当您添加一条数据之后,直接返回列表首页(适合基础数据管理场景)。 -
true:执行智能切换,当您添加一条数据之后,直接从添加表单页跳转到编辑页(适合补充更新的场景)。
选项:操作类
操作类的选项从两个维度对当前列表的 操作按钮 进行控制,参考配置如下:
{
"op.open.add": "添加",
"op.batch.edit": "批量更新",
"op.batch.delete": "批量删除",
"op.extra.column": "修改显示列",
"op.extra.export": "导出",
"op.extra.import": "导入",
"op.extra.view": "视图管理",
"op.row.edit": true,
"op.row.delete": true,
"op.submit.add": "添加",
"op.submit.save": "保存",
"op.submit.delete": "删除",
"op.submit.reset": "重置",
"id.submit.add": "$opAdd",
"id.submit.save": "$opSave",
"id.submit.reset": "$opReset",
"id.submit.delete": "$opDelete"
}
操作类选项都是设置的列表中按钮上的文字,若不存在则直接删除此操作,存在则表示启用。比较特殊的情况就是设置成布尔中的 false,也会直接被关闭,上述配置中我刻意将 连接点 和操作控制配置分开。
op.open.add
列表内 open 区域( 添加操作区域 )内的主按钮,直接从列表页引导打开 mode=ADD 页签将用户引导到 添加表单页。
早期的版本中,open 区域还存在一个按钮 op.open.filter,此按钮负责清除查询条件,这个按钮存在的原因是早期的 ExListComplex 的数据流规划有问题,这个 BUG 已经在新版本中解决了,若您的配置中还碰到了此选项可以直接拿掉。
op.batch.edit
列表内 batch 区域内的 批量更新 按钮,此按钮的触发会受到列表中选择数据的影响,只有您选择了数据记录之后才可点击此按钮。
|
此操作依赖 |
op.batch.delete
列表内 batch 区域内的 批量删除 按钮,此按钮的触发必须让用户选中数据记录才可用(所有的删除级操作都会被 确认类 的选项影响,做前端的一个简单的删除拦截)。
op.extra.column
列表内 extra 区域内的 列筛选 按钮,列筛选按钮可以帮助用户更改当前列的 个人视图,您可以根据您想要查看的模型的列定义个人视图,定义之后您个人看到的列信息会保存在 个人视图 中,并且可通过 视图管理 进行再次调整。
|
(有默认值)此操作依赖 |
op.extra.export
列表内 extra 区域内的 导出 按钮,导出按钮会打开弹窗让用户自定义将要导出的列信息,然后导出 模板化 的文件,现阶段导出版本支持:列选择、列排序 的功能。
|
(有默认值)此操作依赖 |
op.extra.import
列表内 extra 区域内的 导入 按钮,导入按钮会打开弹框让用户上传 模板化 数据文件,然后导入数据记录。
|
(有默认值)此操作依赖 |
op.extra.view
列表内 extra 区域内的 视图管理 按钮,此按钮是一个入口,用户点击之后可进入视图管理界面管理当前环境中的所有 个人视图,个人视图可实现针对视图的 增、删、改 的基本操作。
|
(有默认值)此操作依赖 |
上述所有配置中标记了(有默认值)的配置证明此配置不依赖组件配置也会有相关的默认行为,若您想要定制窗口中的各种文字,则可以追加新配置,新配置会覆盖 默认值。
op.row.edit
列表行上的 编辑 按钮,若此处为 false 则直接导致编辑功能失效。
op.row.delete
列表行上的 删除 按钮,若此处为 false 则直接导致删除功能失效。
op.row.view
若您关闭了 编辑 按钮,您可以设置此值为查看按钮的文字,直接将行中的 编辑 转换成 查看,这个配置可以让您的系统还原到传统的四页面(列表、添加、编辑、查看)流模式。
|
关于 行操作 需要说明的是,它的权限会受到几个不同维度的影响,而不单纯的选项关闭,若您的选项打开也有可能导致行操作失效:
上述维度都是更改 行操作 的维度点,不同场景会有所区别。 |
op.submit.add
当您打开添加页签( mode=ADD ),右上角显示的 添加 按钮的文字设置。
op.submit.reset
当您打开添加页签( mode=ADD ),右上角显示的 重置 按钮的文字设置。
op.submit.save
当您打开编辑页签( mode=EDIT ),右上角显示的 保存 按钮的文字设置。
op.submit.delete
当您打开编辑页签( mode=EDIT ),右上角显示的 删除 按钮的文字设置。
id.submit.add
表单上的 连接点,添加表单( mode=ADD )中的添加按钮。列表页中右上角的按钮位于 <Tabs/> 组件的 Extra 区域,并未位于页签内的表单组件中。
|
参考如下截图: 前文提到的
|
所以示例中设置的 id.submit.add 实际就是表单中 $opAdd,添加,SUBMIT,primary 解析的第一个值,而此按钮的触发依靠的是 op.submit.add 这个按钮触发。
id.submit.reset
表单上的 连接点,添加表单( mode=ADD )中的重置按钮。
id.submit.save
表单上的 连接点,编辑表单( mode=EDIT )中的保存按钮。
id.submit.delete
表单上的 连接点,编辑表单( mode=EDIT )中的删除按钮。
选项:窗口类
整个 ExListComplex 有五个子窗口,每个窗口会包含两部分配置
-
外层窗口配置(窗口类选项配置)
-
内层组件配置(在
component中配置)
参考配置:
{
"window.batch.editor": "选择批量更新的字段,更新,关闭,false,640,true,btnBatchEdit",
"window.extra.column": "请选择您要显示的列,leftTop,640,true",
"window.extra.export": "选择导出字段,导出,关闭,false,720,true,btnExport",
"window.extra.import": "请上传导入文件,导入,关闭,false,720,true,btnImport",
"window.extra.view": "视图管理,right,400,true,btnView"
}
window.batch.editor
批量编辑弹出窗口配置,组件配置位于 component 中的 batch.editor 中。
window.extra.column
列选择浮游窗口配置,组件配置位于 component 中的 extra.column 中。
window.extra.export
导出弹出窗口配置,组件配置位于 component 中的 extra.export 中。
window.extra.import
导入弹出窗口配置,组件配置位于 component 中的 extra.import 中。
window.extra.view
视图管理抽屉窗口配置,组件配置位于 component 中的 extra.view 中。
选项:Ajax类
远程通信类的配置直接和 zero-crud 中的 15 个API地址绑定,由于操作是位于 Op.js 中,所以单记录的 添加、保存、删除 的 API 配置未存在于选项配置中。
参考如下配置:
{
"ajax.search.uri": "/api/room-rent/search",
"ajax.get.uri": "/api/room-rent/:key",
"ajax.delete.uri": "/api/room-rent/:key",
"ajax.batch.delete.uri": "/api/batch/room-rent/delete",
"ajax.batch.update.uri": "/api/batch/room-rent/update",
"ajax.column.full": "/api/columns/room-rent/full",
"ajax.column.my": "/api/columns/room-rent/my",
"ajax.column.save": "/api/columns/room-rent/my",
"ajax.file.export": "/api/room-rent/export",
"ajax.file.import": "/api/room-rent/import"
}
ajax.search.uri
HTTP方法:POST,列表页主接口,支持服务端分页、排序、列过滤功能,Zero 中标准的 Qr 语法接口,有时也作为辅助数据提取的接口来使用。
ajax.get.uri
HTTP方法:GET,单记录读取主接口,查看页和编辑页打开之前访问此接口读取数据记录。
ajax.delete.uri
HTTP方法:DELETE,单记录删除主接口,行删除 和编辑页的 删除 按钮都会使用此接口。
ajax.batch.delete.uri
HTTP方法:DELETE,多记录批量删除主接口。
ajax.batch.update.uri
HTTP方法:PUT,多记录批量更新主接口。
ajax.column.full
HTTP方法:GET,若开启了 动态列 功能,列表会从此接口直接拉取模型所有的 可用属性集,而不再使用 table.columns 中的配置,此接口用于加载 全列 配置数据。
ajax.column.my
HTTP方法:GET,不论是否开启 动态列 功能,此接口和后端 zero-rbac 配合读取个人视图,个人视图有两部分内容是会影响列表的:
-
criteria:当前视图使用的默认的查询条件。 -
projection:当前视图使用的默认的列过滤(我的列)信息。
ajax.column.save
HTTP方法:PUT,若您使用了 查询条件 管理和 列筛选保存 两个按钮提供的管理功能时,会触发此接口刷新个人在当前列表的视图信息。
ajax.file.export
HTTP方法:POST,导出方法专用接口。
ajax.file.import
HTTP方法:POST,导入方法专用接口。
|
上述标准化的接口是 |
选项:拦截类
拦截类选项主要用于在操作之前的进一步提示,通常会给用户一个 confirmation 的确认过程。
配置参考:
{
"confirm.delete": "确认删除当前租借记录?",
"confirm.batch.delete": "您确认要删除所有选中的租借记录?",
"confirm.clean.filter": "该操作将清空所有的查询条件,确认?",
"message.batch.delete": "您所选择的记录已经全部删除成功!"
}
confirm.delete
单记录删除之前的确认,配置之后在删除之前会有提示信息。
confirm.batch.delete
批量删除之前的用户确认信息。
confirm.clean.filter
查询条件删除之前的用户确认信息。
message.batch.delete
批量删除之后呈现的成功信息。
message.batch.update
批量更新之后呈现的成功信息。
列渲染
列表类中的配置节点 table 基本是和 AndD 中的 <Table/> 对齐的配置,所以 列渲染 中没有那么多需要讲解的;本章主要讲解 table.columns 中的列渲染,让开发人员对列的 Zero 中列渲染功能有所了解。
列渲染的 解析器 配置如:
| 索引 | 属性 | 含义 |
|---|---|---|
0 |
|
绑定的记录对应的属性名。 |
1 |
|
当前列的列标题。 |
2 |
|
列的渲染类型,该类型在列表章节详细解析。 |
3 |
|
是否打开列排序,如果打开则列中会启用排序功能。 |
4 |
|
专用键值对处理。 |
在列渲染中,大部分列都支持如下两个特殊属性:
-
$empty:此属性用于描述文本内容为null, undefined, ""时应该呈现的文字信息。 -
$expr:此属性让您呈现的文本可以支持字符串的格式化模式,如:":value间"这种。 -
style:此属性描述了当前列的样式,不经过 CSS 控制。 -
className:此属性描述了当前列的样式,通过 CSS 控制。 -
width:(数值)若您不需要 Zero 自动计算列宽度(有时候会不准),您可以指定当前列的宽度,那么本列就会使用您定义的固定宽度呈现。
ARRAY
此列渲染用于渲染 [] 格式的数据,将内容渲染成列表:
参考配置:
[
"username,在住宾客,ARRAY",
]
另一种附加配置,在附加配置中您可以设置风格以及CSS相关配置对列表的样式进行调整。
[
{
"metadata": "field,title,ARRAY",
"style": {},
"className": ""
}
]
CONNECT (保留)
此列渲染器为保留的行为连接列渲染器,您可以配置多个链接操作,操作本身可以从 reference 的状态变量中提取。
参考配置:
[
{
"metadata": "field,title,CONNECT",
"$option": [
"添加",
"删除"
]
}
]
使用场景
当有多个链接时,您可以构造类似 添加 | 删除 的链接列表,这种模式下 reference 的状态数据结构必须遵循如下
{
"$connect": [
{
"config": {
"pos": "链接到 column.dataIndex"
}
}
]
}
CURRENCY
货币格式的列渲染器。
参考配置:
[
{
"metadata": "field,title,CURRENCY",
"$config": {
"unit": "¥",
"after": "true | false"
}
}
]
货币转换时会自动转换成带有 千分位 的货币数值格式。
| 配置项 | 含义 |
|---|---|
|
渲染的货币单位。 |
|
货币单位的位置:
|
DATE
日期格式的列渲染器。
参考配置:
[
{
"metadata": "field,title,DATE",
"$format": "YYYY-MM-DD",
"$config": {
"format": ""
}
}
]
此处会根据 format 中定义的模式格式化当前日期信息,只是此处有两种配置:
-
旧版:(保留)直接使用
$format配置项来描述日期时间格式。 -
新版:使用
$config.format配置来描述日期时间格式。
DATUM
字典(辅助数据)的列渲染器
参考配置:
[
{
"metadata": "field,title,DATUM",
"$datum": "source=bill.type,value=code,display=name",
"$config": {
"adorn": {
"field": "f1",
"items": {
"record[f1]": "icon,size,color",
"record[f2]": "icon,size,color"
}
}
}
}
]
此列渲染器主要负责渲染字典列,它支持的功能如下:
-
直接绑定当前页面的字典信息:
配置项 含义 source字典名字,在辅助数据章节有所说明。
value字典值的字段名(后台存储的就是这部分的值)。
display字典显示字段名,这个属性可以支持
$expr的格式。表单中的配置和列渲染中的配置有区别,主要是最后部分,表单是
label=name,而列渲染是display=name,这是历史原因,这里就不多提了,目前新版的前端 API 针对这种表达式都可执行解析了,但标准配置还是以文档为主,不会出错。 -
给字典信息追加图标定义,这个功能是修饰功能,此处的
f1一定会是一个维度字段( 非 主键 类型),所有数据记录中包含几种值,不同的值图标定义可以不相同。
DICT
纯字典类型
参考配置:
[
{
"metadata": "field,title,DICT",
"$config": {
"field": "xxx"
}
}
]
这种字典类型会直接从组件的 props 中提取 特殊字典 $dict 变量中的数据对列进行渲染,此处的 field 默认会使用 name,也可以提取其他属性信息。参考示例如下:
[
{
"metadata": "valueNew,新值,DICT",
"$config": {
"field": "fieldName"
},
"className": "value-column"
}
]
DOWNLOAD
下载链接渲染列
参考配置:
[
{
"metadata": "field,title,DOWNLOAD",
"$config": {
"ajax": {
"uri": "/api/xxxx/download/:key"
}
}
}
]
上述配置会渲染一个下载链接,下载链接中包含了 ajax 的部分(可自定义),此处存放的就是下载链接地址,点击之后就可以下载相关文件。
EDITOR
自定义表格列编辑器
参考配置:
[
{
"metadata": "field,title,EDITOR",
"$config": {
"render": "aiSelect",
"optionJsx.config.items": [
"GET,GET方法",
"PUT,PUT方法"
]
}
}
]
这种渲染一般用于自定义表格列编辑器,它会渲染行内编辑行为,目前支持的行内编辑组件如下(由于没有全部做过测试,此处只是根据源代码中梳理的组件逻辑,验证过的是目前已经在使用的):
| 渲染器 | 验证 | 含义 |
|---|---|---|
|
Ok |
(默认值)文本框 |
|
Ok |
数值输入器 |
|
Ok |
单选框 |
|
Ok |
树型下拉框 |
|
Ok |
多选框 |
|
Ok |
时间选择器 |
|
Ok |
日期选择器 |
|
Ok |
下拉框 |
|
Ok |
协议输入器 |
|
Ok |
验证码输入 |
|
Ok |
密码输入 |
|
富文本输入框 |
|
|
地址选择器 |
|
|
JSON 格式多选器 |
|
|
穿梭框 |
|
|
批量上传 |
|
|
图片上传 |
|
|
上传组件 |
|
|
数组型文本录入 |
|
|
JSON 编辑器 |
注:此处作为表格内编辑器时,配置项直接位于 $config 内,除了 render 以外,其他配置和表格中配置等价。
EXECUTOR
操作列专用渲染器
参考配置:
[
{
"metadata": "field,title,EXECUTOR",
"$option": [
{
"text": "编辑",
"executor": "fnEdit"
},
"divider",
{
"text": "删除",
"executor": "fnDelete",
"confirm": "确认删除选择记录"
}
]
}
]
上述配置是常用列表的配置,一般配置 EXECUTOR 时必须通过编程的方式从外层填充 $executor 变量。
|
参考下边的返回数据结构:
注意上述结构中实际是使用了 二阶函数 在生成
此处的 参数表
|
$executor 的扩展配置实际是整个开发流程中 高频 定制的地方,它让您的 ExListComplex 多了很多 行扩展 的可能性,您可以直接根据您的需要在一个列表的行中定制各种所需的的操作,唯一不能定制的是此处的操作是链接,此处无法定制其他样式的操作按钮。
FILE_SIZE
文件尺寸专用渲染器
参考配置:
[
{
"metadata": "field,title,FILE_SIZE"
}
]
此列渲染器专用于渲染文件尺寸,它把一个数值直接转换成文件尺寸,并且自动追加单位:B, KB, MB, GB, TB。
HYPERLINK
链接渲染器
参考配置:
[
{
"metadata": "name,名称,HYPERLINK",
"$config": {
"url": "/person/circle-view?id=:key"
}
}
]
其配置项如:
| 配置项 | 含义 |
|---|---|
|
当前链接制定的路由地址
|
LAZY
延迟加载列渲染器
参考配置:
[
{
"metadata": "openBy,制单人,USER",
"$config": {
"uri": "/api/user/:key",
"field": "realname",
"icon": "user,#00BF9F"
}
}
]
其配置项如:
| 配置项 | 含义 |
|---|---|
|
此处一般是 |
|
远程读取的数据一般是 |
|
是否在呈现的属性中追加图标信息, |
|
此处有一点需说明,这个 列渲染器 有两个值:
定义的接口的语义:根据当前属性的值填充 而且有一点, |
LOGICAL
布尔值渲染器
参考配置:
[
{
"metadata": "income,消费/付款,LOGICAL",
"$mapping": {
"true": "消费项,pay-circle,16,#268941",
"false": "付款项,pay-circle,16,#f6af03"
}
}
]
注意此处启用了特殊属性 $mapping 而不是 $config,这也是为了契合映射语义设计的机制,它表示从 值 到 呈现 的强语义关系。此处的值的配置启用了 解析表达式,对应的语义为:
| 索引值 | 属性名 | 含义 |
|---|---|---|
0 |
|
值对应的显示文本 |
1 |
|
此值定义的图标信息 |
2 |
|
定义图标时图标的大小(推荐使用 `14 / 16`等) |
3 |
|
定义了图标的色彩 |
MAPPING
多值映射渲染器
参考配置:
[
{
"metadata": "method,HTTP方法,MAPPING",
"$mapping": {
"GET": "GET,download,,#268941",
"PUT": "PUT,edit,,#0a7bed",
"POST": "POST,plus,,#f6af03",
"DELETE": "DELETE,delete,,#e22015"
}
}
]
此渲染器和 LOGICAL 使用的配置用法完全一致,只是二者的使用场景不同:
-
LOGICAL一般用于后端的属性是boolean值的情况,字面量只有true / false,它属于MAPPING的 子集。 -
MAPPING不限定类型,适用性更广泛,但弱化了布尔值(开关型)的语义,所以才有会单独的LOGICAL的渲染器。
PERCENT
百分比渲染器
参考配置:
[
{
"metadata": "field,title,PERCENT"
},
...,
"field,title,PERCENT"
]
此渲染器是百分比渲染器,目前不支持任何配置,只是单纯把浮点数如 0.123 转换成 12.3%,后期可以考虑追加精度来完成百分比的增强渲染(注意此时值必须是一个可以转换成数值的值,不可以是 NaN)。
PURE
纯文本高亮显示器
参考配置:
[
{
"metadata": "field,title,PURE",
"highlight": true
},
...,
"field,title,PURE"
]
支持 高亮 语法的渲染器,通常会根据您输入的关键字对文本中内容执行高亮,当系统启用高亮语法时,您需要保证您的 React 组件状态 state 拥有如下数据结构:
{
"$keyword": {
"field1": "xxxx",
"field2": "xxxx"
}
}
此处的 field1, field2 若和当前 dataIndex 匹配的话,那么对应的 xxxx 在文本值中的部分会直接被高亮呈现。
RENDERS
编程模式,自定义扩展型渲染器
参考配置:
[
{
"metadata": "sourceCode,配置项编号,RENDERS",
"config": {
"value": "code",
"mapping": {
"globalId": "sourceGlobalId",
"name": "sourceName",
"identifier": "sourceIdentifier"
}
}
}
]
这是一个特殊渲染器,它提取的是 React 组件属性 props 中的 $renders 变量,此变量结构如下:
{
"field1": (props) => {
},
"field2": Jsx
}
您可以从外层直接传入两种不同形态的渲染模型(函数型、组件型),系统会自动按照 Zero 中的继承模式将对应属性传入到渲染器中,这个组件接收到的核心 props 中的变量如:
{
"value": "当前属性的值",
"config": "当前列的配置",
"data": "当前行记录全值"
}
ROW
早期以为 EDITOR 和 ROW 的性质相同,现在发现此两种列渲染区别很大:
-
EDITOR:多用于自定义表格中处理,且<Form/>可以将整个表格的列单独抽取成可编辑的。 -
ROW:通常用于行编辑(带索引)-
若在
<Form/>中,则reference.props.value的值可以作为表单中渲染的值。 -
若在外层中,也可以使用
reference.props.value来处理控制列等信息。
-
参考配置:
[
{
"metadata": "field,title,ROW",
"$config": {
"field": "aiTreeSelect",
"jsx": {
"style": {
},
"config": {
"datum": "source=term.expense,key=key,label=code",
"__COMMENT": "xxxx"
}
}
}
}
]
常用的配置数据 $config 如下:
|
正常模式下, |
| 属性 | 含义 |
|---|---|
|
等价于 |
|
等价于 |
|
默认值( |
|
(已废弃),新版本会直接连接 |
代码中的属性使用
// value = []
// fieldCond = `key`
// record.key = record[format.keyField]
const foundIndex = __Zn.elementIndex(value, fieldCond, record[format.keyField]);
TAG
标签渲染器,标签渲染器相对比较简单,根据您的数据值的不同格式执行从 <img/> 和 <Icon/> 切换:
| 格式 | 含义 |
|---|---|
|
直接将值转换成 |
|
将 |
新版标签渲染器追加了标签的独立渲染功能,可直接渲染 antd 中的 <Tag/> 标签,生成如下列信息:
|
新版标签渲染器需配合
还有一点需注意是这种渲染器是为 antd 中的 |
TEXT
(默认)文本渲染器,此渲染器是唯一一个不需要配置的渲染器,属于 默认渲染器,此渲染器到处都是,就不详细拆解了。
TOTAL
求和渲染器(计算渲染器)
参考配置:
[
{
"metadata": "amount,金额,TOTAL",
"$config": {
"currency": "¥",
"op": "M",
"field": [
"quantity",
"price"
]
}
}
]
其配置项如:
| 配置项 | 含义 |
|---|---|
|
货币单位 |
|
计算符号
|
|
字段合计,针对哪些字段执行求和操作(一般是同行的属性) |
列过滤
前边章节讲解了 列渲染 相关内容,最后看看列表中的 列过滤,列过滤部分直接上配置,主要配置如下:
-
$filter.type:列过滤类型。 -
$filter.config:此类型对应的配置信息。
SEARCH
搜索框类型:
[
{
"metadata": "name,圈子名称,,true",
"$filter.type": "SEARCH",
"$filter.config": {
"placeholder": "输入名称",
"button": {
"search": "搜索",
"reset": "重置"
}
}
}
]
DIRECT (默认)
布尔选择类型:
[
{
"metadata": "active,是否启用,LOGICAL,true",
"$mapping": {
"true": "启用",
"false": "禁用"
},
"$filter.config.dataType": "BOOLEAN",
"$filter.config.items": [
"true,启用",
"false,禁用"
],
"$filter.config.button": {
"yes": "确认",
"reset": "重置"
},
"$filter.config.width": {
"radio": 110,
"button": 55
}
}
]
DATUM
字典类型:
[
{
"metadata": "floor,楼层,DATUM",
"$datum": "xxxxx",
"$filter.type": "DATUM",
"$filter.config.button": {
"yes": "确认",
"reset": "重置"
}
}
]
定制化开发
本章讲解列表定制化开发部分,当您使用了列表组件 ExListComplex / ExListFast 之后,您可以参考本章的引导对标准列表进行操作定制,列渲染和过滤本身的定制目前先不讲解,后续遇到之后会逐步开放。
本章节的定制化开发主要是针对开发人员对标准列表进行扩展和定制开发,所以不支持直接配置的模式,后期版本开通 SSR 功能之后可以让行为在服务端实现直接定制,就可以打开配置功能。
添加区域
定制步骤
在标准的列表中( ExListComplex 组件),它的头部主要分为了四个区域,本章节定制添加区域,参考如下截图:
本章节详细讲解如何拓展新增区域并追加一个按钮以实现次区域的定制,您可以按照如下步骤进行:
-
在
options节点中配置op.extension.xxx这种前缀为op.extension的操作按钮节点{ "_grid": { "...": "...", "options": { "...": "...", "op.extension.generate": { "text": "批量发卡", "icon": "build", "className": "uc_green", "region": "op.open.card", "config": { "executor": "rxCard" } }, "op.extension.reject": { "text": "批量拒绝", "region": "op.batch.reject", "plugin": { "prompt": "confirm.batch.reject" }, "config": { "index": 1, "executor": "rxReject", "ajax": { "uri": "/api/todo/reject", "method": "POST" }, "message": "message.batch.approval" } } } } }在 Zero UI 中有一个基本限制,就是扩展
ExListXxx类似的组件时,所有扩展区域的按钮必须以op.extension作为操作前缀,只有这种类型的前缀会被捕捉到并扩展到相对应的区域。解读一下上述配置的具体细节:配置项 含义 op.extension.generate这是最早的配置项,不同的按钮其名称有所区别,这个名字只要不重复,您就可以无限扩展(当然也取决于您的添加区域的宽度),此处的按钮系统名称为
op.extension.generate。text此按钮显示的文字信息。
icon此按钮上显示的图标,图标扩展会追溯到
AntD 3.x中的<Icon type=""/>,现在虽然升级了不能使用这种语法,可 Zero Ui 做了版本的兼容处理,这种配置依旧生效(Ux.v4Icon方法)。className当前按钮的风格信息,常用的风格参考对应章节,
uc_开头,全称为Uniform Color。region这个属性比较重要,按照列表本身的区域配置,头部会包含四个核心区域:
open, batch, search, extra,这四个区域中支持按钮扩展的只有open, batch, extra,所以此处命名方式遵循约定赋值到region属性中,此属性的含义如下:-
op.open前缀:表示按钮会追加到open区域(本例中)。 -
op.batch前缀:表示按钮追加到batch区域。 -
op.extra前缀:表示按钮追加到extra区域。
如示例中实际拓展了两个按钮,一个位于
open区域,一个位于batch区域。plugin插件体系一般是按钮在
batch区域时使用,此插件体系的完整版如:{ "op.extension.approval": { "...": "...", "plugin": { "window": "window.batch.approval", "componentType": "ExApprovalBatch", "component": "batch.approval" } } }此处的节点配置主要做对接扩展,配置的内容是自由格式,您可以根据自己按钮部分的定制选择使用哪种配置,此处的
approval插件是参考的批量处理按钮的配置在设置,但实际格式取决于您开发的扩展按钮的内部逻辑。config配置项,配置项是半自由格式,主要两个影响前端布局的属性如下:
-
executor:当前执行函数的函数名,一般是点击操作之后的函数绑定专用。 -
index:当前按钮的顺序,有了index之后可以对您的extension扩展进行排序,所有的extension的按钮基本位置是追加在原始的op.batch按钮之后,可以使用index进行重排。
-
-
为
rxReject处配置的executor定制外置函数。const rxReject = () => (reference, config = {}) => (event) => { Ux.prevent(event); return Ux.sexBatch(reference, (keys = []) => { const {ajax = {}} = config; return Ux.asyncPromise(ajax, {keys}); }, {name: "rxBatchApproval", message: config.message}); };此处注意,上述函数此处是一个三阶函数,每一阶含义如下:
-
三阶:
(),此处虽然没有带参数,但实际使用过程中它在最外层中,您实际是可以传入您想要的外置参数的。 -
二阶:
(reference, config = {}),此处两个参数有待注意,reference实际是组件ExListXxx的引用,而不是外层引用;config则包含了上述配置中的config节点之下的所有内容。 -
一阶:
(event),直接绑定到按钮点击事件中。
-
-
再看一个
rxCard对应的executor的配置:const rxCard = (ref) => (reference) => (event) => Ux.of(ref).open().done();此处的基础定义和前一步骤是一致的,同样是一个三阶函数,每一个阶的含义如下:
-
三阶:
(ref):此处带有参数,实际ref表示的是最外层组件的组件引用,此处属于外置参数。 -
二阶:
(reference):此处没有开放config函数,其实此处也不需要开放第一参,只是单纯为了让开发人员找到ExListXxx的组件引用,所以保留了reference参数。 -
一阶:
(event),直接绑定到按钮点击事件中。
-
高阶 vs 绑定
注意:在列表定制开发中,此处头部区域的按钮绑定的都是 三阶函数,此处实质上 ExListXxx 组件中消费都是二阶函数,参考如下图示:
实际上这个三阶函数的第三阶已经在调用组件外层就转换成二阶了,传入组件之后还会执行一次组件引用的绑定 (reference, config),这次绑定会彻底生成最下层的按钮所需的 (event) 事件函数,这样的结构就让开发人员在书写函数时可以根据自己需要选择对应的引用去提取相关数据。这种设计在 Zero UI 中十分常见,很多开发人员不理解高阶函数的实用场景,参考下图:
-
如果您的事件函数体书写在
UI.js中,结构/行为/显示三者不分离,此时函数内可以使用this拿到React组件引用。 -
但是若您将原来的
UI.js拆分成UI.js 和 Op.js两个文件时,想要在Op.js中拿到React组件引用,您就可以考虑多一阶的方式去处理。 -
如此操作之后,您依旧可以在函数内部使用
reference代替this拿到组件引用。
|
此处诱发另外一个思考:为什么不直接使用 在 Zero Ui 中大量使用了高阶替换了 JavaScript 中的函数 当然,不推荐部代表您不可以使用 |
行区域
在标准的列表中( ExListComplex 组件),行区域定制主要针对表格行操作链接(默认是链接,您可以切换成按钮),参考下图(角色管理):
默认规则
Zero Ui 中的 ExListXxx 类型的列表组件的列渲染中有一类 EXECUTOR 用于处理操作列,先参考角色管理中的列处理配置:
[
{
"title": "操作",
"dataIndex": "key",
"fixed": "left",
"$render": "EXECUTOR",
"$option": [
{
"text": "编辑",
"executor": "fnEdit"
},
"divider",
{
"text": "删除",
"executor": "fnDelete",
"confirm": "确认删除选择的角色记录?"
},
"divider",
{
"text": "权限设置",
"executor": "fnAuthorize"
}
]
}
]
上述配置是角色管理中的三个按钮的基本配置,在列表行区域的默认规则如:
executor 名称 |
含义 |
|---|---|
|
对应编辑表单专用的执行器,表单对应 |
|
对应删除操作专用的执行器,表单对应 |
在通用的中后台管理模块中,fnEdit 和 fnDelete 属于默认配置,基本规则如下:
-
二者配置的时候无需额外配置,直接配置后会按照列表的基础配置呈现并执行相关规则。
-
您可以直接使用
divider值呈现两个链接之间的分割线,这种格式配置为固定配置。 -
若您未配置
fnEdit,则可以默认开启查看功能(只读模式):{ "op.row.edit": false, "op.row.delete": false, "op.row.view": "查看" }
扩展行
Zero Ui中扩展行配置如前边角色扮演所示,直接配置过程中您可以追加一个新的按钮如:
[
{
"text": "权限设置",
"executor": "fnAuthorize"
}
]
注意:这种模式并非纯配置模式,而是依赖编程开发扩展函数,此函数的脚本示例如下:
<ExListComplex {...Ex.yoAmbient(this)}
$executor={{
fnAuthorize: (roleId, record = {}) => Ex.aclRoute(this, {
key: roleId,
view: "ROLE",
data: record,
})
}}
config={config} $form={form}/>
上述 fnAuthorize 为行定制专用函数,此函数签名您可以参考列渲染章节,此处由于开发脚本存在于同一个文件 UI.js 中,所以并没有使用高阶函数绑定事件,而是直接定义了函数,采用了 this 引用。
关于四个区域的扩展,等后边深度定制的时候再提供教程来梳理,不同区域的函数签名略微有些差异。
示例:extra 操作
本章节看一个详细的例子(零点提供)来查看右上角的定制部分:
此处可以看到,点击进入详情页之后,此处的按钮已经被重新定制过了,且定制成了自定义的模式(此处使用了 Smart 开发模式)。
-
关闭和定制列表的选项:
{ Options: { rm: [ "form.add", // 关闭添加表单 "form.filter", // 关闭高级搜索表单 "op.open.add", // 按钮:添加 "op.extra.export", // 按钮:导出 "op.extra.import", // 按钮:导入 "op.batch.edit", // 按钮:批量编辑 "op.batch.delete", // 按钮:批量删除 "op.submit.add", // 内页:添加提交 "op.submit.save", // 内页:编辑提交 "op.submit.delete", // 内页:删除提交 "op.submit.reset", // 内页:重置 ] }, Form: { name: "FormBook", FormEdit } }有一点注意,此处的
FormEdit是自定义编辑表单。 -
挂载右上的按钮部分:
yoRx: (reference) => ({ rxPostClose: () => Fn.ioOrderClose(reference, {$booked: false}), rxExtraEdit: (data, ref, fnJsx) => Jx.aiPayMenu(reference, data, fnJsx), })此处挂载了两个
rx函数,其含义分别如下:-
rxPostClose:此函数和右上的按钮没有任何关系,只是单纯提供了核心函数方法,此方法在关闭页签之后触发:Post Close。 -
rxExtraEdit:此函数为核心渲染方法,它有三个参数:data表示当前界面绑定的远程数据记录的基础数据;ref是外层的 React 组件引用;fnJsx是挂载的外层Jsx渲染器,界面呈现就是依赖此处的rxExtraEdit来扩展定制。
-
-
行操作触发函数(行区域扩展):
yoExecutor: (reference) => ({ fnIncome: Ex.rxRowOpen(reference, { // 打开后操作 rxAfter: (bookKey, record) => Fn.ioOrderOpen(reference, record, {bookKey}), }), fnView: Ex.rxRowOpen(reference, { // 调用订单关闭时的操作 rxAfter: (id, record) => reference.setState({$booked: true}), }), })这里调用了
Ex中的rxRowOpen来打开行相关内容,说明一下几个点:-
此处的
fnIncome / fnView就是行配置中的EXECUTOR配置中对应的executor配置属性。 -
rxAfter / rxBefore是所有的executor自定义扩展都可以直接定义的前置操作和后置操作。
-
-
行状态控制——行状态控制是更加细粒度的控制操作,您可以根据当前行的记录数据控制哪些链接显示哪些链接不显示,此处主要定制:
koRow函数:yoPlugins: (reference) => ({ // 行操作 koRow: (record, config, ref) => { if ("Finished" === record.status) { return "fnView" === config.executor; } else { return "fnIncome" === config.executor; } } })先解释下上述的控制逻辑,直接检查记录中的
status属性:-
若
status=Finished表示已完成的账单,这种情况会触发fnView的执行器(fnView执行器是直接从fnEdit转换过来的查看执行器,不用配置,切换查看页面流专用 )。 -
若
status的值不是Finished则执行fnIncome的执行器,继续执行管理操作。
这样配置之后,这个模块的行就包含了行双态,行的数据会影响行的按钮行为,这个功能在很多场景中都可以使用。
-
此处放出完整的定制模块源代码,让读者对此有更深刻的理解:
UI.json
{
"_assist": {
"tabular": {
"uri": "/api/types/tabulars",
"method": "POST",
"magic": {
"$body": [
"preorder.category",
"preorder.method",
"surety.type",
"code.source",
"code.market",
"code.pricecat",
"order.status",
"zero.customer",
"gender.type",
"idc.type",
"bill.type",
"bill.status",
"bill.category",
"pay.term.type",
"in.room.type"
]
},
"group": "type"
},
"room.type": {
"uri": "/api/room-type/by/sigma"
},
"code.price": {
"uri": "/api/room-price/hotel/:hid",
"magic": {
"hid": "PROP:app.mHotel.key"
}
}
},
"_grid": {
"query": {
"criteria": {
"sigma": "PROP:app.sigma",
"": true,
"major": "BOOL:false"
}
},
"module": {
"NAME": "账本",
"MODULE": "fm-book",
"IDENTIFIER": "fm.bank"
},
"options": {
"search.advanced": false,
"op.row.edit": false,
"op.row.delete": false,
"op.row.view": false,
"tabs.edit": "账务管理"
},
"table": {
"columns": [
{
"title": "操作",
"dataIndex": "key",
"fixed": "left",
"width": 80,
"$render": "EXECUTOR",
"$option": [
{
"text": "账务处理",
"executor": "fnIncome",
"ajax": {
"uri": "/api/order/:orderId"
}
},
{
"text": "查看账本",
"executor": "fnView"
}
]
}
]
},
"synonym": {
"modelKey": "房号"
}
}
}
UI.js
import Ui from "ui";
import Ex from 'ex';
import FormEdit from './UI.Form';
import {Fn, Jx} from "app";
import Ux from "ux";
export default Ui.smartList({
ns: require("./Cab.json"),
name: "PxBook",
Options: {
rm: [
"form.add", // 关闭添加表单
"form.filter", // 关闭高级搜索表单
"op.open.add", // 按钮:添加
"op.extra.export", // 按钮:导出
"op.extra.import", // 按钮:导入
"op.batch.edit", // 按钮:批量编辑
"op.batch.delete", // 按钮:批量删除
"op.submit.add", // 内页:添加提交
"op.submit.save", // 内页:编辑提交
"op.submit.delete", // 内页:删除提交
"op.submit.reset", // 内页:重置
]
},
Form: {
name: "FormBook",
FormEdit
},
yoRx: (reference) => ({
rxPostClose: () => Fn.ioOrderClose(reference, {$booked: false}),
rxExtraEdit: (data, ref, fnJsx) => Jx.aiPayMenu(reference, data, fnJsx),
}),
yoExecutor: (reference) => ({
fnIncome: Ex.rxRowOpen(reference, {
// 打开后操作
rxAfter: (bookKey, record) => Fn.ioOrderOpen(reference, record, {bookKey}),
}),
fnView: Ex.rxRowOpen(reference, {
// 调用订单关闭时的操作
rxAfter: (id, record) => reference.setState({$booked: true}),
}),
}),
yoPlugins: (reference) => ({
// 行操作
koRow: (record, config, ref) => {
if ("Finished" === record.status) {
return "fnView" === config.executor;
} else {
return "fnIncome" === config.executor;
}
}
}),
componentInit: (reference) => {
Ex.yiAssist(reference)
.then(Ux.ready)
.then(Ux.pipe(reference));
},
componentYo: (reference, inherit = {}) => {
const {$booked} = reference.state;
if ($booked) {
// 查看账本,如果有特殊逻辑则在此处加新代码
} else {
// 订单处理
Fn.yoBill(reference, inherit);
}
// 设置 $entry
inherit.$entry = "BILL";
return inherit;
}
})
若您仔细阅读了前边章节的列表定制,那么这样两份代码是没有任何难度的;除了本章提到的扩展以外,实际在定制过程中还有很多扩展方式无法一一梳理,也没法书写相关细节,等到后续案例章节来一一说明。
自定义开发
组件:DocViewer
本章带大家一起开发一个文档阅览器,文档阅览器主要用于从远程 X_ATTACHMENT 生成的属性中加载对应的文件信息,实现 Word, PPT, Excel, PDF 四种不同文件的阅览功能,这是一个新的自定义组件,且不会生成 aiX 的交互式组件,仅做文档预览专用。开发文档阅览器使用的库如:
|
旧版本从2020年开始已经没有运维了(最新版 |
环境搭建
在您的项目中执行如下命令添加依赖包:
# NPM 模式安装
npm install --save @onlyoffice/document-editor-react
# YARN 模式安装
yarn add @onlyoffice/document-editor-react
这是一个标准化组件,可以直接扔到 economy 中去实现,实际在这个项目内您可以看到目录前缀( @ 符号之前 )如下截图:
上述结构中 @ 之前的拼写表示这个组件来自于哪个内部项目,即 z 开头的一系列底层项目,由于 DocViewer 的目的是做文档阅览,所以此处选择直接放到最上层处理:
| 前缀 | 目录 | 含义 |
|---|---|---|
|
|
直接在标准组件中定义文档阅览器,此处有个特殊点在于此文档阅览器会解析 |
按照如下步骤创建此自定义组件( 自定义组件只能在项目 https://gitee.com/silentbalanceyh/scaffold-ui.git 中开发,ai sync 命令会读取此项目做框架层同步 ):
-
在
economy目录下创建一个新目录:web@DocViewer。 -
按照 Zero Ui 的基础规范,目录中创建入口文件
UI.js,文件内容如下:旧版写法(class模式)
import React from 'react'; class Component extends React.PureComponent { render() { return ( <div> <h1>Doc Viewer</h1> </div> ); } } export default Component;新版写法(hook模式)
import React from 'react'; const Component = (props) => { return ( <div> <h1>Doc Viewer</h1> </div> ); } export default Component;新旧版本的选择在于您是否要启用
Ux.zero的注解,若使用注解和资源文件绑定,那么依旧采用class模式开放是最好的选择,若您的组件内部无需启用资源文件绑定的功能,那么可以直接使用hook模式开发。 -
写好之后更改入口文件
index.js / index.d.ts:// 都追加如下导出信息: export {default as DocViewer} from './web@DocViewer/UI'; // 消费端使用: import {DocViewer} from 'web'; -
提交
scaffold-ui中的 PR 并且在自己项目中执行ai sync同步对应代码就可以使得此组件生效了。
文件下载
文档阅览器中使用的数据结构在 Zero Ui 中是直接对齐了 X_ATTACHMENT 记录的数据结构,此数据结构如:
{
"key": "???",
"name": "论文范文.docx",
"extension": "docx",
"type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"mime": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"size": 16644,
"status": "DONE",
"directoryId": "???",
"storeWay": "STORE",
"storePath": "/apps/nm/document/合规文档/法规库/LAW2309071001/论文范文.docx",
"modelId": "nm.law",
"modelKey": "???",
"modelCategory": "DOC.NORM.LAW",
"fileName": "论文范文",
"fileKey": "???",
"fileUrl": "/api/file/download/xxx-of-download",
"filePath": "file-uploads/xxx-of-upload",
"active": true,
"sigma": "???",
"metadata": {},
"language": "cn",
"createdAt": "2023-09-07T11:44:23",
"createdBy": "???",
"updatedAt": "2023-09-07T11:44:23",
"updatedBy": "???",
"visitGroup": null,
"visitRole": null,
"visitMode": [
"r",
"w",
"x"
],
"visit": false,
"directory": false
}
上述数据结构描述了远程存储的文件基本信息,此处对文件阅览器而言,最核心属性如:
| 属性 | 含义 |
|---|---|
|
文件原始名称,下载时也可以使用此名称存储到客户端。 |
|
文件的MIME,此属性很重要,它描述了远程文件的核心格式,虽然文档阅览器可以通过后缀名对文件类型进行区分,但 |
|
下载文件专用的地址,内置会调用 |
|
文件唯一键,此唯一键在后端可跨任何系统做全局唯一的标识,从云存储角度打破了所属的维度概念,简单说整个平台上传的文件都只有一个唯一的`fileKey`。 |
由于 DocViewer 使用的是 class 模式的开发,文件下载流程应该在 componentDidMount 方法中设置,并在预览之前初始化好组件状态。